aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/blackfin/kgdb.txt155
-rw-r--r--Documentation/feature-removal-schedule.txt8
-rw-r--r--Documentation/filesystems/ext4.txt5
-rw-r--r--Documentation/filesystems/proc.txt7
-rw-r--r--Documentation/kernel-parameters.txt26
-rw-r--r--Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl3
-rw-r--r--Documentation/sparc/sbus_drivers.txt309
-rw-r--r--Documentation/timers/00-INDEX10
-rw-r--r--Documentation/timers/hpet.txt (renamed from Documentation/hpet.txt)43
-rw-r--r--MAINTAINERS872
-rw-r--r--arch/Kconfig14
-rw-r--r--arch/alpha/Kconfig4
-rw-r--r--arch/alpha/include/asm/statfs.h4
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/include/asm/statfs.h34
-rw-r--r--arch/arm/kernel/dma.c17
-rw-r--r--arch/arm/mach-orion5x/include/mach/orion5x.h2
-rw-r--r--arch/arm/plat-omap/devices.c21
-rw-r--r--arch/avr32/boards/atngw100/setup.c19
-rw-r--r--arch/avr32/boards/atstk1000/atstk1002.c23
-rw-r--r--arch/avr32/boards/atstk1000/atstk1003.c15
-rw-r--r--arch/avr32/boards/atstk1000/atstk1004.c18
-rw-r--r--arch/avr32/include/asm/a.out.h20
-rw-r--r--arch/avr32/include/asm/atmel-mci.h32
-rw-r--r--arch/avr32/include/asm/byteorder.h22
-rw-r--r--arch/avr32/include/asm/io.h8
-rw-r--r--arch/avr32/kernel/process.c3
-rw-r--r--arch/avr32/kernel/setup.c19
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c460
-rw-r--r--arch/avr32/mach-at32ap/clock.c52
-rw-r--r--arch/avr32/mach-at32ap/clock.h8
-rw-r--r--arch/avr32/mach-at32ap/include/mach/at32ap700x.h128
-rw-r--r--arch/avr32/mach-at32ap/include/mach/board.h2
-rw-r--r--arch/avr32/mach-at32ap/include/mach/io.h3
-rw-r--r--arch/avr32/mach-at32ap/include/mach/portmux.h5
-rw-r--r--arch/avr32/mach-at32ap/pdc.c3
-rw-r--r--arch/avr32/mach-at32ap/pio.c63
-rw-r--r--arch/avr32/oprofile/Makefile2
-rw-r--r--arch/avr32/oprofile/backtrace.c81
-rw-r--r--arch/avr32/oprofile/op_model_avr32.c4
-rw-r--r--arch/blackfin/Kconfig75
-rw-r--r--arch/blackfin/Kconfig.debug55
-rw-r--r--arch/blackfin/Makefile1
-rw-r--r--arch/blackfin/configs/BF526-EZBRD_defconfig1427
-rw-r--r--arch/blackfin/configs/H8606_defconfig36
-rw-r--r--arch/blackfin/include/asm/a.out.h19
-rw-r--r--arch/blackfin/include/asm/bfin-global.h5
-rw-r--r--arch/blackfin/include/asm/bfrom.h85
-rw-r--r--arch/blackfin/include/asm/cacheflush.h2
-rw-r--r--arch/blackfin/include/asm/cplb.h8
-rw-r--r--arch/blackfin/include/asm/cplbinit.h16
-rw-r--r--arch/blackfin/include/asm/cpumask.h6
-rw-r--r--arch/blackfin/include/asm/dma-mapping.h11
-rw-r--r--arch/blackfin/include/asm/kgdb.h21
-rw-r--r--arch/blackfin/include/asm/mmu_context.h79
-rw-r--r--arch/blackfin/include/asm/processor.h6
-rw-r--r--arch/blackfin/include/asm/ptrace.h2
-rw-r--r--arch/blackfin/include/asm/traps.h5
-rw-r--r--arch/blackfin/kernel/asm-offsets.c1
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c13
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c9
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbinit.c12
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c14
-rw-r--r--arch/blackfin/kernel/cplb-nompu/cplbinit.c6
-rw-r--r--arch/blackfin/kernel/early_printk.c12
-rw-r--r--arch/blackfin/kernel/kgdb.c711
-rw-r--r--arch/blackfin/kernel/ptrace.c215
-rw-r--r--arch/blackfin/kernel/reboot.c18
-rw-r--r--arch/blackfin/kernel/setup.c97
-rw-r--r--arch/blackfin/kernel/traps.c367
-rw-r--r--arch/blackfin/mach-bf527/boards/Kconfig5
-rw-r--r--arch/blackfin/mach-bf527/boards/Makefile1
-rw-r--r--arch/blackfin/mach-bf527/boards/cm_bf527.c17
-rw-r--r--arch/blackfin/mach-bf527/boards/ezbrd.c734
-rw-r--r--arch/blackfin/mach-bf527/boards/ezkit.c53
-rw-r--r--arch/blackfin/mach-bf527/head.S3
-rw-r--r--arch/blackfin/mach-bf527/include/mach/anomaly.h160
-rw-r--r--arch/blackfin/mach-bf527/include/mach/bf527.h21
-rw-r--r--arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h6
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF52x_base.h27
-rw-r--r--arch/blackfin/mach-bf527/include/mach/portmux.h4
-rw-r--r--arch/blackfin/mach-bf533/boards/H8606.c34
-rw-r--r--arch/blackfin/mach-bf533/head.S3
-rw-r--r--arch/blackfin/mach-bf533/include/mach/anomaly.h49
-rw-r--r--arch/blackfin/mach-bf533/include/mach/bf533.h12
-rw-r--r--arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h6
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c85
-rw-r--r--arch/blackfin/mach-bf537/head.S3
-rw-r--r--arch/blackfin/mach-bf537/include/mach/anomaly.h2
-rw-r--r--arch/blackfin/mach-bf537/include/mach/bf537.h12
-rw-r--r--arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h6
-rw-r--r--arch/blackfin/mach-bf548/boards/cm_bf548.c22
-rw-r--r--arch/blackfin/mach-bf548/boards/ezkit.c58
-rw-r--r--arch/blackfin/mach-bf548/head.S52
-rw-r--r--arch/blackfin/mach-bf548/include/mach/anomaly.h93
-rw-r--r--arch/blackfin/mach-bf548/include/mach/bf548.h25
-rw-r--r--arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h6
-rw-r--r--arch/blackfin/mach-bf548/include/mach/mem_map.h14
-rw-r--r--arch/blackfin/mach-bf561/head.S3
-rw-r--r--arch/blackfin/mach-bf561/include/mach/anomaly.h2
-rw-r--r--arch/blackfin/mach-bf561/include/mach/bf561.h8
-rw-r--r--arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h6
-rw-r--r--arch/blackfin/mach-bf561/include/mach/mem_map.h18
-rw-r--r--arch/blackfin/mach-common/entry.S219
-rw-r--r--arch/blackfin/mach-common/head.S52
-rw-r--r--arch/blackfin/mach-common/interrupt.S11
-rw-r--r--arch/blackfin/mach-common/ints-priority.c25
-rw-r--r--arch/blackfin/mm/Makefile2
-rw-r--r--arch/blackfin/mm/isram-driver.c201
-rw-r--r--arch/blackfin/mm/sram-alloc.c (renamed from arch/blackfin/mm/blackfin_sram.c)31
-rw-r--r--arch/cris/arch-v10/boot/tools/build.c1
-rw-r--r--arch/h8300/Kconfig3
-rw-r--r--arch/h8300/include/asm/a.out.h20
-rw-r--r--arch/h8300/kernel/process.c1
-rw-r--r--arch/ia64/include/asm/a.out.h32
-rw-r--r--arch/ia64/include/asm/siginfo.h5
-rw-r--r--arch/ia64/include/asm/statfs.h52
-rw-r--r--arch/ia64/mm/init.c1
-rw-r--r--arch/m32r/Kconfig3
-rw-r--r--arch/m68k/Kconfig4
-rw-r--r--arch/m68knommu/Kconfig3
-rw-r--r--arch/m68knommu/include/asm/a.out.h1
-rw-r--r--arch/m68knommu/kernel/process.c1
-rw-r--r--arch/m68knommu/kernel/traps.c1
-rw-r--r--arch/mips/include/asm/a.out.h35
-rw-r--r--arch/mips/kernel/process.c1
-rw-r--r--arch/mips/kernel/syscall.c1
-rw-r--r--arch/mn10300/Kconfig3
-rw-r--r--arch/parisc/Kconfig3
-rw-r--r--arch/powerpc/include/asm/a.out.h20
-rw-r--r--arch/powerpc/include/asm/siginfo.h5
-rw-r--r--arch/powerpc/include/asm/statfs.h54
-rw-r--r--arch/powerpc/kernel/softemu8xx.c1
-rw-r--r--arch/powerpc/kernel/traps.c1
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c2
-rw-r--r--arch/powerpc/platforms/chrp/setup.c1
-rw-r--r--arch/powerpc/platforms/maple/setup.c1
-rw-r--r--arch/powerpc/platforms/powermac/setup.c1
-rw-r--r--arch/powerpc/platforms/pseries/setup.c1
-rw-r--r--arch/s390/hypfs/inode.c2
-rw-r--r--arch/s390/include/asm/statfs.h11
-rw-r--r--arch/sparc/Kconfig26
-rw-r--r--arch/sparc/include/asm/Kbuild4
-rw-r--r--arch/sparc/include/asm/asmmacro.h5
-rw-r--r--arch/sparc/include/asm/bpp.h73
-rw-r--r--arch/sparc/include/asm/bugs.h7
-rw-r--r--arch/sparc/include/asm/cpudata_64.h1
-rw-r--r--arch/sparc/include/asm/dma-mapping_32.h59
-rw-r--r--arch/sparc/include/asm/dma.h141
-rw-r--r--arch/sparc/include/asm/dma_32.h288
-rw-r--r--arch/sparc/include/asm/dma_64.h205
-rw-r--r--arch/sparc/include/asm/ebus.h8
-rw-r--r--arch/sparc/include/asm/ebus_32.h99
-rw-r--r--arch/sparc/include/asm/ebus_64.h95
-rw-r--r--arch/sparc/include/asm/ebus_dma.h35
-rw-r--r--arch/sparc/include/asm/elf_32.h7
-rw-r--r--arch/sparc/include/asm/fhc.h43
-rw-r--r--arch/sparc/include/asm/floppy_32.h16
-rw-r--r--arch/sparc/include/asm/floppy_64.h130
-rw-r--r--arch/sparc/include/asm/gpio.h36
-rw-r--r--arch/sparc/include/asm/io-unit.h4
-rw-r--r--arch/sparc/include/asm/io_32.h19
-rw-r--r--arch/sparc/include/asm/io_64.h22
-rw-r--r--arch/sparc/include/asm/iommu_64.h3
-rw-r--r--arch/sparc/include/asm/irq_64.h1
-rw-r--r--arch/sparc/include/asm/mc146818rtc_64.h10
-rw-r--r--arch/sparc/include/asm/memctrl.h9
-rw-r--r--arch/sparc/include/asm/mostek.h8
-rw-r--r--arch/sparc/include/asm/mostek_32.h171
-rw-r--r--arch/sparc/include/asm/mostek_64.h143
-rw-r--r--arch/sparc/include/asm/obio.h11
-rw-r--r--arch/sparc/include/asm/of_device.h2
-rw-r--r--arch/sparc/include/asm/of_platform.h3
-rw-r--r--arch/sparc/include/asm/oplib_32.h1
-rw-r--r--arch/sparc/include/asm/page_32.h5
-rw-r--r--arch/sparc/include/asm/page_64.h2
-rw-r--r--arch/sparc/include/asm/parport.h4
-rw-r--r--arch/sparc/include/asm/pci_32.h2
-rw-r--r--arch/sparc/include/asm/pgtable_32.h4
-rw-r--r--arch/sparc/include/asm/pgtable_64.h2
-rw-r--r--arch/sparc/include/asm/prom.h12
-rw-r--r--arch/sparc/include/asm/ptrace_64.h3
-rw-r--r--arch/sparc/include/asm/reboot.h6
-rw-r--r--arch/sparc/include/asm/rtc.h26
-rw-r--r--arch/sparc/include/asm/sbus.h8
-rw-r--r--arch/sparc/include/asm/sbus_32.h153
-rw-r--r--arch/sparc/include/asm/sbus_64.h190
-rw-r--r--arch/sparc/include/asm/serial.h6
-rw-r--r--arch/sparc/include/asm/spinlock_32.h2
-rw-r--r--arch/sparc/include/asm/spinlock_64.h2
-rw-r--r--arch/sparc/include/asm/sstate.h13
-rw-r--r--arch/sparc/include/asm/starfire.h1
-rw-r--r--arch/sparc/include/asm/statfs.h8
-rw-r--r--arch/sparc/include/asm/statfs_32.h6
-rw-r--r--arch/sparc/include/asm/statfs_64.h54
-rw-r--r--arch/sparc/include/asm/sun4paddr.h56
-rw-r--r--arch/sparc/include/asm/sun4prom.h83
-rw-r--r--arch/sparc/include/asm/system_32.h9
-rw-r--r--arch/sparc/include/asm/system_64.h6
-rw-r--r--arch/sparc/include/asm/thread_info_32.h4
-rw-r--r--arch/sparc/include/asm/timer_32.h87
-rw-r--r--arch/sparc/include/asm/vac-ops.h7
-rw-r--r--arch/sparc/include/asm/vfc_ioctls.h58
-rw-r--r--arch/sparc/include/asm/visasm.h1
-rw-r--r--arch/sparc/kernel/Makefile4
-rw-r--r--arch/sparc/kernel/apc.c72
-rw-r--r--arch/sparc/kernel/auxio.c6
-rw-r--r--arch/sparc/kernel/devices.c2
-rw-r--r--arch/sparc/kernel/dma.c227
-rw-r--r--arch/sparc/kernel/dma.h14
-rw-r--r--arch/sparc/kernel/ebus.c393
-rw-r--r--arch/sparc/kernel/entry.S94
-rw-r--r--arch/sparc/kernel/head.S28
-rw-r--r--arch/sparc/kernel/idprom.c7
-rw-r--r--arch/sparc/kernel/ioport.c227
-rw-r--r--arch/sparc/kernel/irq.h6
-rw-r--r--arch/sparc/kernel/of_device.c74
-rw-r--r--arch/sparc/kernel/pcic.c15
-rw-r--r--arch/sparc/kernel/pmc.c59
-rw-r--r--arch/sparc/kernel/process.c2
-rw-r--r--arch/sparc/kernel/prom.c7
-rw-r--r--arch/sparc/kernel/setup.c32
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c25
-rw-r--r--arch/sparc/kernel/sun4c_irq.c156
-rw-r--r--arch/sparc/kernel/sun4d_irq.c286
-rw-r--r--arch/sparc/kernel/sun4d_smp.c13
-rw-r--r--arch/sparc/kernel/sun4m_irq.c495
-rw-r--r--arch/sparc/kernel/sun4m_smp.c5
-rw-r--r--arch/sparc/kernel/sun4setup.c75
-rw-r--r--arch/sparc/kernel/sys_sparc.c8
-rw-r--r--arch/sparc/kernel/tick14.c47
-rw-r--r--arch/sparc/kernel/time.c382
-rw-r--r--arch/sparc/kernel/traps.c17
-rw-r--r--arch/sparc/mm/Makefile9
-rw-r--r--arch/sparc/mm/btfixup.c6
-rw-r--r--arch/sparc/mm/fault.c2
-rw-r--r--arch/sparc/mm/init.c14
-rw-r--r--arch/sparc/mm/io-unit.c136
-rw-r--r--arch/sparc/mm/iommu.c113
-rw-r--r--arch/sparc/mm/nosrmmu.c59
-rw-r--r--arch/sparc/mm/srmmu.c1
-rw-r--r--arch/sparc/mm/sun4c.c204
-rw-r--r--arch/sparc/prom/Makefile2
-rw-r--r--arch/sparc/prom/bootstr.c4
-rw-r--r--arch/sparc/prom/console.c3
-rw-r--r--arch/sparc/prom/init.c12
-rw-r--r--arch/sparc/prom/memory.c14
-rw-r--r--arch/sparc/prom/ranges.c1
-rw-r--r--arch/sparc/prom/sun4prom.c161
-rw-r--r--arch/sparc64/Kconfig23
-rw-r--r--arch/sparc64/Makefile2
-rw-r--r--arch/sparc64/kernel/Makefile9
-rw-r--r--arch/sparc64/kernel/auxio.c2
-rw-r--r--arch/sparc64/kernel/central.c617
-rw-r--r--arch/sparc64/kernel/chmc.c817
-rw-r--r--arch/sparc64/kernel/cpu.c208
-rw-r--r--arch/sparc64/kernel/ds.c4
-rw-r--r--arch/sparc64/kernel/ebus.c299
-rw-r--r--arch/sparc64/kernel/entry.h7
-rw-r--r--arch/sparc64/kernel/head.S1
-rw-r--r--arch/sparc64/kernel/hvapi.c3
-rw-r--r--arch/sparc64/kernel/hvcalls.S354
-rw-r--r--arch/sparc64/kernel/irq.c1
-rw-r--r--arch/sparc64/kernel/of_device.c62
-rw-r--r--arch/sparc64/kernel/pci.c172
-rw-r--r--arch/sparc64/kernel/pci_common.c8
-rw-r--r--arch/sparc64/kernel/pci_fire.c254
-rw-r--r--arch/sparc64/kernel/pci_impl.h27
-rw-r--r--arch/sparc64/kernel/pci_msi.c18
-rw-r--r--arch/sparc64/kernel/pci_psycho.c750
-rw-r--r--arch/sparc64/kernel/pci_sabre.c507
-rw-r--r--arch/sparc64/kernel/pci_schizo.c368
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c197
-rw-r--r--arch/sparc64/kernel/pci_sun4v_asm.S99
-rw-r--r--arch/sparc64/kernel/power.c55
-rw-r--r--arch/sparc64/kernel/process.c35
-rw-r--r--arch/sparc64/kernel/prom.c91
-rw-r--r--arch/sparc64/kernel/psycho_common.c470
-rw-r--r--arch/sparc64/kernel/psycho_common.h48
-rw-r--r--arch/sparc64/kernel/ptrace.c38
-rw-r--r--arch/sparc64/kernel/reboot.c53
-rw-r--r--arch/sparc64/kernel/sbus.c166
-rw-r--r--arch/sparc64/kernel/smp.c4
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c23
-rw-r--r--arch/sparc64/kernel/sstate.c67
-rw-r--r--arch/sparc64/kernel/starfire.c5
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c8
-rw-r--r--arch/sparc64/kernel/syscalls.S20
-rw-r--r--arch/sparc64/kernel/systbls.S2
-rw-r--r--arch/sparc64/kernel/time.c1187
-rw-r--r--arch/sparc64/kernel/traps.c69
-rw-r--r--arch/sparc64/kernel/vio.c8
-rw-r--r--arch/sparc64/kernel/visemul.c12
-rw-r--r--arch/sparc64/mm/fault.c37
-rw-r--r--arch/sparc64/mm/init.c84
-rw-r--r--arch/sparc64/mm/init.h49
-rw-r--r--arch/sparc64/mm/tlb.c2
-rw-r--r--arch/um/Kconfig.i3868
-rw-r--r--arch/um/Kconfig.x86_643
-rw-r--r--arch/um/drivers/line.c2
-rw-r--r--arch/x86/Kconfig96
-rw-r--r--arch/x86/Kconfig.cpu93
-rw-r--r--arch/x86/Kconfig.debug13
-rw-r--r--arch/x86/Makefile_32.cpu6
-rw-r--r--arch/x86/boot/Makefile5
-rw-r--r--arch/x86/boot/compressed/Makefile8
-rw-r--r--arch/x86/boot/edd.c7
-rw-r--r--arch/x86/boot/video-vesa.c2
-rw-r--r--arch/x86/configs/i386_defconfig2
-rw-r--r--arch/x86/configs/x86_64_defconfig2
-rw-r--r--arch/x86/ia32/ia32_signal.c68
-rw-r--r--arch/x86/ia32/ia32entry.S26
-rw-r--r--arch/x86/kernel/Makefile12
-rw-r--r--arch/x86/kernel/acpi/boot.c12
-rw-r--r--arch/x86/kernel/alternative.c2
-rw-r--r--arch/x86/kernel/amd_iommu_init.c4
-rw-r--r--arch/x86/kernel/apic_32.c4
-rw-r--r--arch/x86/kernel/apic_64.c4
-rw-r--r--arch/x86/kernel/cpu/common.c56
-rw-r--r--arch/x86/kernel/doublefault_32.c2
-rw-r--r--arch/x86/kernel/dumpstack_32.c447
-rw-r--r--arch/x86/kernel/dumpstack_64.c573
-rw-r--r--arch/x86/kernel/early-quirks.c48
-rw-r--r--arch/x86/kernel/early_printk.c748
-rw-r--r--arch/x86/kernel/entry_32.S22
-rw-r--r--arch/x86/kernel/entry_64.S15
-rw-r--r--arch/x86/kernel/es7000_32.c28
-rw-r--r--arch/x86/kernel/genx2apic_uv_x.c23
-rw-r--r--arch/x86/kernel/head.c1
-rw-r--r--arch/x86/kernel/hpet.c6
-rw-r--r--arch/x86/kernel/i387.c14
-rw-r--r--arch/x86/kernel/io_apic_64.c4
-rw-r--r--arch/x86/kernel/irqinit_64.c43
-rw-r--r--arch/x86/kernel/ldt.c9
-rw-r--r--arch/x86/kernel/microcode.c853
-rw-r--r--arch/x86/kernel/microcode_amd.c435
-rw-r--r--arch/x86/kernel/microcode_core.c508
-rw-r--r--arch/x86/kernel/microcode_intel.c480
-rw-r--r--arch/x86/kernel/paravirt-spinlocks.c37
-rw-r--r--arch/x86/kernel/paravirt.c27
-rw-r--r--arch/x86/kernel/process_32.c43
-rw-r--r--arch/x86/kernel/process_64.c33
-rw-r--r--arch/x86/kernel/ptrace.c44
-rw-r--r--arch/x86/kernel/quirks.c41
-rw-r--r--arch/x86/kernel/setup.c206
-rw-r--r--arch/x86/kernel/signal_32.c222
-rw-r--r--arch/x86/kernel/signal_64.c207
-rw-r--r--arch/x86/kernel/smp.c6
-rw-r--r--arch/x86/kernel/smpboot.c164
-rw-r--r--arch/x86/kernel/time_32.c7
-rw-r--r--arch/x86/kernel/time_64.c23
-rw-r--r--arch/x86/kernel/tlb_32.c8
-rw-r--r--arch/x86/kernel/traps.c (renamed from arch/x86/kernel/traps_32.c)895
-rw-r--r--arch/x86/kernel/traps_64.c1214
-rw-r--r--arch/x86/kernel/vmlinux_64.lds.S2
-rw-r--r--arch/x86/kernel/xsave.c33
-rw-r--r--arch/x86/mach-generic/es7000.c20
-rw-r--r--arch/x86/mm/Makefile6
-rw-r--r--arch/x86/mm/fault.c19
-rw-r--r--arch/x86/mm/gup.c10
-rw-r--r--arch/x86/mm/init_32.c5
-rw-r--r--arch/x86/mm/init_64.c12
-rw-r--r--arch/x86/mm/ioremap.c170
-rw-r--r--arch/x86/mm/numa_32.c (renamed from arch/x86/mm/discontig_32.c)0
-rw-r--r--arch/x86/mm/srat_64.c2
-rw-r--r--arch/x86/oprofile/Makefile2
-rw-r--r--arch/x86/oprofile/nmi_int.c27
-rw-r--r--arch/x86/oprofile/op_model_amd.c543
-rw-r--r--arch/x86/oprofile/op_model_athlon.c190
-rw-r--r--arch/x86/oprofile/op_x86_model.h4
-rw-r--r--arch/x86/pci/fixup.c28
-rw-r--r--arch/x86/xen/Kconfig12
-rw-r--r--arch/x86/xen/Makefile12
-rw-r--r--arch/x86/xen/debugfs.c123
-rw-r--r--arch/x86/xen/debugfs.h10
-rw-r--r--arch/x86/xen/enlighten.c252
-rw-r--r--arch/x86/xen/irq.c143
-rw-r--r--arch/x86/xen/mmu.c314
-rw-r--r--arch/x86/xen/mmu.h3
-rw-r--r--arch/x86/xen/multicalls.c115
-rw-r--r--arch/x86/xen/smp.c245
-rw-r--r--arch/x86/xen/spinlock.c428
-rw-r--r--arch/x86/xen/time.c12
-rw-r--r--arch/x86/xen/xen-asm_32.S2
-rw-r--r--arch/x86/xen/xen-asm_64.S22
-rw-r--r--arch/x86/xen/xen-ops.h8
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/glue.c3
-rw-r--r--drivers/ata/Kconfig1
-rw-r--r--drivers/atm/fore200e.c410
-rw-r--r--drivers/atm/fore200e.h7
-rw-r--r--drivers/block/sunvdc.c4
-rw-r--r--drivers/block/xen-blkfront.c2
-rw-r--r--drivers/bluetooth/hci_ldisc.c2
-rw-r--r--drivers/char/Kconfig4
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/amiserial.c6
-rw-r--r--drivers/char/applicom.c6
-rw-r--r--drivers/char/cyclades.c21
-rw-r--r--drivers/char/epca.c5
-rw-r--r--drivers/char/generic_serial.c21
-rw-r--r--drivers/char/hpet.c159
-rw-r--r--drivers/char/hvc_console.c4
-rw-r--r--drivers/char/hvc_xen.c6
-rw-r--r--drivers/char/hw_random/n2-drv.c2
-rw-r--r--drivers/char/ip2/Makefile2
-rw-r--r--drivers/char/ip2/i2ellis.c32
-rw-r--r--drivers/char/ip2/i2ellis.h2
-rw-r--r--drivers/char/ip2/ip2base.c108
-rw-r--r--drivers/char/ip2/ip2main.c550
-rw-r--r--drivers/char/isicom.c61
-rw-r--r--drivers/char/istallion.c113
-rw-r--r--drivers/char/moxa.c61
-rw-r--r--drivers/char/mxser.c193
-rw-r--r--drivers/char/n_hdlc.c2
-rw-r--r--drivers/char/n_r3964.c8
-rw-r--r--drivers/char/n_tty.c125
-rw-r--r--drivers/char/nozomi.c5
-rw-r--r--drivers/char/pcmcia/ipwireless/tty.c19
-rw-r--r--drivers/char/pty.c335
-rw-r--r--drivers/char/rtc.c30
-rw-r--r--drivers/char/stallion.c139
-rw-r--r--drivers/char/sx.c4
-rw-r--r--drivers/char/tpm/tpm.c96
-rw-r--r--drivers/char/tpm/tpm.h3
-rw-r--r--drivers/char/tpm/tpm_tis.c14
-rw-r--r--drivers/char/tty_audit.c2
-rw-r--r--drivers/char/tty_buffer.c511
-rw-r--r--drivers/char/tty_io.c1380
-rw-r--r--drivers/char/tty_ioctl.c212
-rw-r--r--drivers/char/tty_port.c96
-rw-r--r--drivers/char/vt.c84
-rw-r--r--drivers/char/vt_ioctl.c2
-rw-r--r--drivers/hwmon/Kconfig7
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ultra45_env.c320
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c2
-rw-r--r--drivers/input/misc/sparcspkr.c4
-rw-r--r--drivers/input/serio/i8042-sparcio.h2
-rw-r--r--drivers/input/xen-kbdfront.c4
-rw-r--r--drivers/isdn/capi/capi.c2
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c27
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-sunfire.c273
-rw-r--r--drivers/media/video/cafe_ccic.c13
-rw-r--r--drivers/mmc/Kconfig9
-rw-r--r--drivers/mmc/card/Kconfig3
-rw-r--r--drivers/mmc/card/block.c46
-rw-r--r--drivers/mmc/card/queue.c23
-rw-r--r--drivers/mmc/core/mmc_ops.c8
-rw-r--r--drivers/mmc/core/sdio.c52
-rw-r--r--drivers/mmc/core/sdio_irq.c16
-rw-r--r--drivers/mmc/host/Kconfig30
-rw-r--r--drivers/mmc/host/atmel-mci-regs.h6
-rw-r--r--drivers/mmc/host/atmel-mci.c1352
-rw-r--r--drivers/mmc/host/mmc_spi.c32
-rw-r--r--drivers/mmc/host/sdhci-pci.c5
-rw-r--r--drivers/mmc/host/sdhci.c46
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mtd/maps/sun_uflash.c75
-rw-r--r--drivers/mtd/nand/cafe_nand.c6
-rw-r--r--drivers/net/au1000_eth.c27
-rw-r--r--drivers/net/bfin_mac.c26
-rw-r--r--drivers/net/e1000/e1000_main.c5
-rw-r--r--drivers/net/jme.c1
-rw-r--r--drivers/net/myri_sbus.c196
-rw-r--r--drivers/net/myri_sbus.h2
-rw-r--r--drivers/net/niu.c2
-rw-r--r--drivers/net/qlge/qlge_ethtool.c1
-rw-r--r--drivers/net/qlge/qlge_main.c1
-rw-r--r--drivers/net/r8169.c3
-rw-r--r--drivers/net/sky2.c19
-rw-r--r--drivers/net/smc911x.c9
-rw-r--r--drivers/net/smc911x.h14
-rw-r--r--drivers/net/sunbmac.c204
-rw-r--r--drivers/net/sunbmac.h4
-rw-r--r--drivers/net/sunhme.c322
-rw-r--r--drivers/net/sunhme.h7
-rw-r--r--drivers/net/sunlance.c180
-rw-r--r--drivers/net/sunqe.c162
-rw-r--r--drivers/net/sunqe.h4
-rw-r--r--drivers/net/sunvnet.c4
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/wan/Kconfig2
-rw-r--r--drivers/net/xen-netfront.c6
-rw-r--r--drivers/oprofile/buffer_sync.c209
-rw-r--r--drivers/oprofile/cpu_buffer.c74
-rw-r--r--drivers/oprofile/cpu_buffer.h2
-rw-r--r--drivers/parport/parport_sunbpp.c49
-rw-r--r--drivers/power/Kconfig2
-rw-r--r--drivers/rtc/Kconfig32
-rw-r--r--drivers/rtc/Makefile3
-rw-r--r--drivers/rtc/rtc-bq4802.c230
-rw-r--r--drivers/rtc/rtc-cmos.c5
-rw-r--r--drivers/rtc/rtc-m48t59.c68
-rw-r--r--drivers/rtc/rtc-starfire.c120
-rw-r--r--drivers/rtc/rtc-sun4v.c153
-rw-r--r--drivers/s390/char/fs3270.c17
-rw-r--r--drivers/sbus/Makefile4
-rw-r--r--drivers/sbus/char/Kconfig29
-rw-r--r--drivers/sbus/char/Makefile6
-rw-r--r--drivers/sbus/char/bbc_envctrl.c121
-rw-r--r--drivers/sbus/char/bbc_i2c.c267
-rw-r--r--drivers/sbus/char/bbc_i2c.h75
-rw-r--r--drivers/sbus/char/bpp.c1055
-rw-r--r--drivers/sbus/char/cpwatchdog.c858
-rw-r--r--drivers/sbus/char/display7seg.c251
-rw-r--r--drivers/sbus/char/envctrl.c147
-rw-r--r--drivers/sbus/char/flash.c130
-rw-r--r--drivers/sbus/char/rtc.c275
-rw-r--r--drivers/sbus/char/uctrl.c216
-rw-r--r--drivers/sbus/char/vfc.h171
-rw-r--r--drivers/sbus/char/vfc_dev.c736
-rw-r--r--drivers/sbus/char/vfc_i2c.c335
-rw-r--r--drivers/sbus/char/vfc_i2c.h44
-rw-r--r--drivers/sbus/dvma.c136
-rw-r--r--drivers/sbus/sbus.c316
-rw-r--r--drivers/scsi/esp_scsi.h3
-rw-r--r--drivers/scsi/qlogicpti.c146
-rw-r--r--drivers/scsi/qlogicpti.h2
-rw-r--r--drivers/scsi/sun_esp.c267
-rw-r--r--drivers/serial/8250.c52
-rw-r--r--drivers/serial/8250_pci.c4
-rw-r--r--drivers/serial/Kconfig17
-rw-r--r--drivers/serial/Makefile16
-rw-r--r--drivers/serial/bfin_5xx.c123
-rw-r--r--drivers/serial/crisv10.c5
-rw-r--r--drivers/serial/mcfserial.c1965
-rw-r--r--drivers/serial/mcfserial.h74
-rw-r--r--drivers/serial/serial_core.c12
-rw-r--r--drivers/serial/sunhv.c2
-rw-r--r--drivers/serial/sunsab.c2
-rw-r--r--drivers/serial/sunsu.c2
-rw-r--r--drivers/serial/sunzilog.c2
-rw-r--r--drivers/usb/core/inode.c2
-rw-r--r--drivers/usb/host/ehci.h138
-rw-r--r--drivers/usb/serial/aircable.c15
-rw-r--r--drivers/usb/serial/belkin_sa.c3
-rw-r--r--drivers/usb/serial/console.c8
-rw-r--r--drivers/usb/serial/cyberjack.c3
-rw-r--r--drivers/usb/serial/cypress_m8.c5
-rw-r--r--drivers/usb/serial/digi_acceleport.c19
-rw-r--r--drivers/usb/serial/empeg.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.c25
-rw-r--r--drivers/usb/serial/garmin_gps.c3
-rw-r--r--drivers/usb/serial/generic.c3
-rw-r--r--drivers/usb/serial/io_edgeport.c43
-rw-r--r--drivers/usb/serial/io_ti.c26
-rw-r--r--drivers/usb/serial/ipaq.c3
-rw-r--r--drivers/usb/serial/ipw.c3
-rw-r--r--drivers/usb/serial/ir-usb.c3
-rw-r--r--drivers/usb/serial/iuu_phoenix.c3
-rw-r--r--drivers/usb/serial/keyspan.c77
-rw-r--r--drivers/usb/serial/keyspan_pda.c16
-rw-r--r--drivers/usb/serial/kl5kusb105.c3
-rw-r--r--drivers/usb/serial/kobil_sct.c3
-rw-r--r--drivers/usb/serial/mct_u232.c6
-rw-r--r--drivers/usb/serial/mos7720.c36
-rw-r--r--drivers/usb/serial/mos7840.c7
-rw-r--r--drivers/usb/serial/navman.c3
-rw-r--r--drivers/usb/serial/omninet.c10
-rw-r--r--drivers/usb/serial/option.c18
-rw-r--r--drivers/usb/serial/oti6858.c7
-rw-r--r--drivers/usb/serial/pl2303.c15
-rw-r--r--drivers/usb/serial/safe_serial.c11
-rw-r--r--drivers/usb/serial/sierra.c16
-rw-r--r--drivers/usb/serial/spcp8x5.c3
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c44
-rw-r--r--drivers/usb/serial/usb-serial.c24
-rw-r--r--drivers/usb/serial/visor.c18
-rw-r--r--drivers/usb/serial/whiteheat.c8
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c4
-rw-r--r--drivers/video/bw2.c2
-rw-r--r--drivers/video/cg14.c2
-rw-r--r--drivers/video/cg3.c2
-rw-r--r--drivers/video/cg6.c38
-rw-r--r--drivers/video/console/Kconfig16
-rw-r--r--drivers/video/ffb.c2
-rw-r--r--drivers/video/leo.c96
-rw-r--r--drivers/video/p9100.c2
-rw-r--r--drivers/video/tcx.c2
-rw-r--r--drivers/video/xen-fbfront.c4
-rw-r--r--drivers/watchdog/Kconfig43
-rw-r--r--drivers/watchdog/Makefile7
-rw-r--r--drivers/watchdog/at91sam9_wdt.c328
-rw-r--r--drivers/watchdog/cpwd.c695
-rw-r--r--drivers/watchdog/it87_wdt.c725
-rw-r--r--drivers/watchdog/omap_wdt.c337
-rw-r--r--drivers/watchdog/omap_wdt.h28
-rw-r--r--drivers/watchdog/orion5x_wdt.c245
-rw-r--r--drivers/watchdog/riowd.c (renamed from drivers/sbus/char/riowatchdog.c)236
-rw-r--r--drivers/watchdog/w83697ug_wdt.c392
-rw-r--r--drivers/xen/Makefile1
-rw-r--r--drivers/xen/balloon.c175
-rw-r--r--drivers/xen/cpu_hotplug.c90
-rw-r--r--drivers/xen/events.c40
-rw-r--r--drivers/xen/grant-table.c2
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c8
-rw-r--r--fs/9p/v9fs.c2
-rw-r--r--fs/Kconfig4
-rw-r--r--fs/Kconfig.binfmt6
-rw-r--r--fs/adfs/super.c2
-rw-r--r--fs/affs/super.c2
-rw-r--r--fs/afs/super.c2
-rw-r--r--fs/autofs/inode.c2
-rw-r--r--fs/autofs4/inode.c2
-rw-r--r--fs/befs/linuxvfs.c2
-rw-r--r--fs/cifs/misc.c2
-rw-r--r--fs/debugfs/inode.c3
-rw-r--r--fs/devpts/inode.c68
-rw-r--r--fs/dquot.c6
-rw-r--r--fs/ecryptfs/main.c2
-rw-r--r--fs/efs/super.c2
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext3/super.c2
-rw-r--r--fs/ext4/ext4.h2
-rw-r--r--fs/ext4/ioctl.c12
-rw-r--r--fs/ext4/super.c43
-rw-r--r--fs/fat/inode.c6
-rw-r--r--fs/fuse/inode.c2
-rw-r--r--fs/gfs2/mount.c2
-rw-r--r--fs/hfs/super.c2
-rw-r--r--fs/hfsplus/options.c2
-rw-r--r--fs/hpfs/super.c2
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--fs/ioctl.c4
-rw-r--r--fs/isofs/inode.c2
-rw-r--r--fs/jbd2/checkpoint.c49
-rw-r--r--fs/jbd2/commit.c10
-rw-r--r--fs/jbd2/journal.c28
-rw-r--r--fs/jbd2/recovery.c7
-rw-r--r--fs/jfs/super.c2
-rw-r--r--fs/nfs/nfsroot.c2
-rw-r--r--fs/nfs/super.c6
-rw-r--r--fs/ocfs2/super.c2
-rw-r--r--fs/omfs/inode.c2
-rw-r--r--fs/open.c3
-rw-r--r--fs/proc/Kconfig10
-rw-r--r--fs/proc/array.c7
-rw-r--r--fs/proc/base.c21
-rw-r--r--fs/proc/inode.c2
-rw-r--r--fs/proc/internal.h2
-rw-r--r--fs/proc/proc_misc.c1
-rw-r--r--fs/proc/proc_sysctl.c6
-rw-r--r--fs/proc/task_mmu.c16
-rw-r--r--fs/proc/task_nommu.c5
-rw-r--r--fs/proc/vmcore.c6
-rw-r--r--fs/ubifs/super.c2
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/ufs/super.c4
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c2
-rw-r--r--include/asm-cris/a.out.h26
-rw-r--r--include/asm-generic/siginfo.h2
-rw-r--r--include/asm-generic/statfs.h65
-rw-r--r--include/asm-m32r/a.out.h20
-rw-r--r--include/asm-parisc/a.out.h20
-rw-r--r--include/asm-parisc/siginfo.h5
-rw-r--r--include/asm-parisc/statfs.h55
-rw-r--r--include/asm-x86/bios_ebda.h17
-rw-r--r--include/asm-x86/boot.h2
-rw-r--r--include/asm-x86/desc.h29
-rw-r--r--include/asm-x86/es7000/mpparse.h1
-rw-r--r--include/asm-x86/fixmap_32.h4
-rw-r--r--include/asm-x86/fixmap_64.h12
-rw-r--r--include/asm-x86/io.h15
-rw-r--r--include/asm-x86/io_64.h3
-rw-r--r--include/asm-x86/ioctls.h6
-rw-r--r--include/asm-x86/irqflags.h21
-rw-r--r--include/asm-x86/kdebug.h3
-rw-r--r--include/asm-x86/kprobes.h9
-rw-r--r--include/asm-x86/mach-default/mach_traps.h6
-rw-r--r--include/asm-x86/microcode.h47
-rw-r--r--include/asm-x86/mmzone_64.h3
-rw-r--r--include/asm-x86/module.h2
-rw-r--r--include/asm-x86/nmi.h4
-rw-r--r--include/asm-x86/page.h8
-rw-r--r--include/asm-x86/page_32.h13
-rw-r--r--include/asm-x86/paravirt.h20
-rw-r--r--include/asm-x86/pgtable.h16
-rw-r--r--include/asm-x86/processor.h35
-rw-r--r--include/asm-x86/ptrace.h6
-rw-r--r--include/asm-x86/segment.h6
-rw-r--r--include/asm-x86/smp.h40
-rw-r--r--include/asm-x86/spinlock.h67
-rw-r--r--include/asm-x86/statfs.h61
-rw-r--r--include/asm-x86/system.h5
-rw-r--r--include/asm-x86/tlbflush.h10
-rw-r--r--include/asm-x86/traps.h85
-rw-r--r--include/asm-x86/xen/hypervisor.h14
-rw-r--r--include/asm-xtensa/a.out.h29
-rw-r--r--include/linux/devpts_fs.h31
-rw-r--r--include/linux/dmi.h41
-rw-r--r--include/linux/elf.h1
-rw-r--r--include/linux/hpet.h14
-rw-r--r--include/linux/jbd2.h5
-rw-r--r--include/linux/kernel.h2
-rw-r--r--include/linux/key.h1
-rw-r--r--include/linux/magic.h4
-rw-r--r--include/linux/mm.h13
-rw-r--r--include/linux/mm_types.h10
-rw-r--r--include/linux/mmc/host.h2
-rw-r--r--include/linux/mmdebug.h18
-rw-r--r--include/linux/mod_devicetable.h47
-rw-r--r--include/linux/oprofile.h2
-rw-r--r--include/linux/parser.h2
-rw-r--r--include/linux/pci_ids.h4
-rw-r--r--include/linux/rtc/m48t59.h47
-rw-r--r--include/linux/sched.h6
-rw-r--r--include/linux/serial.h16
-rw-r--r--include/linux/serial_core.h2
-rw-r--r--include/linux/termios.h15
-rw-r--r--include/linux/tty.h45
-rw-r--r--include/linux/tty_driver.h56
-rw-r--r--include/linux/usb/ehci_def.h160
-rw-r--r--include/linux/vt_kern.h2
-rw-r--r--include/net/cipso_ipv4.h55
-rw-r--r--include/net/netlabel.h51
-rw-r--r--include/sound/core.h3
-rw-r--r--include/sound/memalloc.h2
-rw-r--r--include/sound/soc-dapm.h1
-rw-r--r--include/xen/balloon.h61
-rw-r--r--include/xen/events.h2
-rw-r--r--init/Kconfig10
-rw-r--r--kernel/acct.c2
-rw-r--r--kernel/auditsc.c9
-rw-r--r--kernel/fork.c5
-rw-r--r--kernel/printk.c16
-rw-r--r--kernel/sched_debug.c2
-rw-r--r--kernel/sys.c4
-rw-r--r--kernel/sysctl.c19
-rw-r--r--lib/Kconfig.debug9
-rw-r--r--lib/cmdline.c2
-rw-r--r--lib/parser.c2
-rw-r--r--mm/shmem.c4
-rw-r--r--mm/vmalloc.c7
-rw-r--r--net/9p/client.c2
-rw-r--r--net/9p/trans_fd.c2
-rw-r--r--net/core/skb_dma_map.c2
-rw-r--r--net/ipv4/cipso_ipv4.c656
-rw-r--r--net/ipv4/ip_gre.c2
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/mac80211/rx.c5
-rw-r--r--net/netfilter/ipvs/Kconfig4
-rw-r--r--net/netfilter/nf_tproxy_core.c1
-rw-r--r--net/netlabel/Makefile3
-rw-r--r--net/netlabel/netlabel_addrlist.c388
-rw-r--r--net/netlabel/netlabel_addrlist.h189
-rw-r--r--net/netlabel/netlabel_cipso_v4.c136
-rw-r--r--net/netlabel/netlabel_cipso_v4.h10
-rw-r--r--net/netlabel/netlabel_domainhash.c393
-rw-r--r--net/netlabel/netlabel_domainhash.h40
-rw-r--r--net/netlabel/netlabel_kapi.c272
-rw-r--r--net/netlabel/netlabel_mgmt.c410
-rw-r--r--net/netlabel/netlabel_mgmt.h59
-rw-r--r--net/netlabel/netlabel_unlabeled.c456
-rw-r--r--net/wireless/core.c1
-rw-r--r--scripts/Kbuild.include4
-rw-r--r--scripts/mod/file2alias.c57
-rw-r--r--security/inode.c3
-rw-r--r--security/selinux/hooks.c234
-rw-r--r--security/selinux/include/netlabel.h44
-rw-r--r--security/selinux/include/objsec.h9
-rw-r--r--security/selinux/netlabel.c280
-rw-r--r--security/selinux/ss/services.c13
-rw-r--r--security/smack/smack_lsm.c5
-rw-r--r--security/smack/smackfs.c4
-rw-r--r--sound/core/memalloc.c48
-rw-r--r--sound/oss/ac97_codec.c2
-rw-r--r--sound/pci/ac97/ac97_patch.c2
-rw-r--r--sound/pci/hda/patch_sigmatel.c50
-rw-r--r--sound/soc/at91/Kconfig17
-rw-r--r--sound/soc/at91/Makefile5
-rw-r--r--sound/soc/at91/at91-ssc.c2
-rw-r--r--sound/soc/at91/eti_b1_wm8731.c349
-rw-r--r--sound/soc/blackfin/Kconfig16
-rw-r--r--sound/soc/blackfin/Makefile3
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c42
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c1
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c240
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c47
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h2
-rw-r--r--sound/soc/codecs/Kconfig11
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ac97.c3
-rw-r--r--sound/soc/codecs/ad1980.c1
-rw-r--r--sound/soc/codecs/ad73311.c107
-rw-r--r--sound/soc/codecs/ad73311.h90
-rw-r--r--sound/soc/codecs/ak4535.c1
-rw-r--r--sound/soc/codecs/ssm2602.c1
-rw-r--r--sound/soc/codecs/tlv320aic23.c714
-rw-r--r--sound/soc/codecs/tlv320aic23.h122
-rw-r--r--sound/soc/codecs/tlv320aic3x.c5
-rw-r--r--sound/soc/codecs/uda1380.c1
-rw-r--r--sound/soc/codecs/wm8510.c111
-rw-r--r--sound/soc/codecs/wm8510.h1
-rw-r--r--sound/soc/codecs/wm8580.c2
-rw-r--r--sound/soc/codecs/wm8731.c1
-rw-r--r--sound/soc/codecs/wm8750.c1
-rw-r--r--sound/soc/codecs/wm8753.c75
-rw-r--r--sound/soc/codecs/wm8753.h4
-rw-r--r--sound/soc/codecs/wm8900.c1
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8971.c1
-rw-r--r--sound/soc/codecs/wm8990.c1
-rw-r--r--sound/soc/codecs/wm9712.c3
-rw-r--r--sound/soc/codecs/wm9713.c3
-rw-r--r--sound/soc/omap/Kconfig8
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/n810.c6
-rw-r--r--sound/soc/omap/omap-mcbsp.c181
-rw-r--r--sound/soc/omap/omap-mcbsp.h16
-rw-r--r--sound/soc/omap/omap-pcm.c4
-rw-r--r--sound/soc/omap/osk5912.c232
-rw-r--r--sound/soc/pxa/corgi.c6
-rw-r--r--sound/soc/pxa/em-x270.c2
-rw-r--r--sound/soc/pxa/poodle.c6
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c4
-rw-r--r--sound/soc/pxa/spitz.c16
-rw-r--r--sound/soc/pxa/tosa.c6
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c72
-rw-r--r--sound/soc/soc-core.c5
-rw-r--r--sound/soc/soc-dapm.c25
-rw-r--r--sound/sparc/amd7930.c85
-rw-r--r--sound/sparc/cs4231.c199
-rw-r--r--sound/sparc/dbri.c89
828 files changed, 33230 insertions, 29170 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 73060819ed9..43827780010 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -159,8 +159,6 @@ hayes-esp.txt
- info on using the Hayes ESP serial driver.
highuid.txt
- notes on the change from 16 bit to 32 bit user/group IDs.
-hpet.txt
- - High Precision Event Timer Driver for Linux.
timers/
- info on the timer related topics
hw_random.txt
diff --git a/Documentation/blackfin/kgdb.txt b/Documentation/blackfin/kgdb.txt
deleted file mode 100644
index 84f6a484ae9..00000000000
--- a/Documentation/blackfin/kgdb.txt
+++ /dev/null
@@ -1,155 +0,0 @@
- A Simple Guide to Configure KGDB
-
- Sonic Zhang <sonic.zhang@analog.com>
- Aug. 24th 2006
-
-
-This KGDB patch enables the kernel developer to do source level debugging on
-the kernel for the Blackfin architecture. The debugging works over either the
-ethernet interface or one of the uarts. Both software breakpoints and
-hardware breakpoints are supported in this version.
-http://docs.blackfin.uclinux.org/doku.php?id=kgdb
-
-
-2 known issues:
-1. This bug:
- http://blackfin.uclinux.org/tracker/index.php?func=detail&aid=544&group_id=18&atid=145
- The GDB client for Blackfin uClinux causes incorrect values of local
- variables to be displayed when the user breaks the running of kernel in GDB.
-2. Because of a hardware bug in Blackfin 533 v1.0.3:
- 05000067 - Watchpoints (Hardware Breakpoints) are not supported
- Hardware breakpoints cannot be set properly.
-
-
-Debug over Ethernet:
-
-1. Compile and install the cross platform version of gdb for blackfin, which
- can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
- "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
- With this selected, option "Full Symbolic/Source Debugging support" and
- "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over (Ethernet)". Add "kgdboe=@target-IP/,@host-IP/" to
- the option "Compiled-in Kernel Boot Parameter" under "Kernel hacking".
-
-4. Connect minicom to the serial port and boot the kernel image.
-
-5. Configure the IP "/> ifconfig eth0 target-IP"
-
-6. Start GDB client "bfin-elf-gdb vmlinux".
-
-7. Connect to the target "(gdb) target remote udp:target-IP:6443".
-
-8. Set software breakpoint "(gdb) break sys_open".
-
-9. Continue "(gdb) c".
-
-10. Run ls in the target console "/> ls".
-
-11. Breakpoint hits. "Breakpoint 1: sys_open(..."
-
-12. Display local variables and function paramters.
- (*) This operation gives wrong results, see known issue 1.
-
-13. Single stepping "(gdb) si".
-
-14. Remove breakpoint 1. "(gdb) del 1"
-
-15. Set hardware breakpoint "(gdb) hbreak sys_open".
-
-16. Continue "(gdb) c".
-
-17. Run ls in the target console "/> ls".
-
-18. Hardware breakpoint hits. "Breakpoint 1: sys_open(...".
- (*) This hardware breakpoint will not be hit, see known issue 2.
-
-19. Continue "(gdb) c".
-
-20. Interrupt the target in GDB "Ctrl+C".
-
-21. Detach from the target "(gdb) detach".
-
-22. Exit GDB "(gdb) quit".
-
-
-Debug over the UART:
-
-1. Compile and install the cross platform version of gdb for blackfin, which
- can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
- "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
- With this selected, option "Full Symbolic/Source Debugging support" and
- "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over (UART)". Set "KGDB: UART port number" to be
- a different one from the console. Don't forget to change the mode of
- blackfin serial driver to PIO. Otherwise kgdb works incorrectly on UART.
-
-4. If you want connect to kgdb when the kernel boots, enable
- "KGDB: Wait for gdb connection early"
-
-5. Compile kernel.
-
-6. Connect minicom to the serial port of the console and boot the kernel image.
-
-7. Start GDB client "bfin-elf-gdb vmlinux".
-
-8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
-
-9. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1".
-
-10. Set software breakpoint "(gdb) break sys_open".
-
-11. Continue "(gdb) c".
-
-12. Run ls in the target console "/> ls".
-
-13. A breakpoint is hit. "Breakpoint 1: sys_open(..."
-
-14. All other operations are the same as that in KGDB over Ethernet.
-
-
-Debug over the same UART as console:
-
-1. Compile and install the cross platform version of gdb for blackfin, which
- can be found at $(BINROOT)/bfin-elf-gdb.
-
-2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
- "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
- With this selected, option "Full Symbolic/Source Debugging support" and
- "Compile the kernel with frame pointers" are also selected.
-
-3. Select option "KGDB: connect over UART". Set "KGDB: UART port number" to console.
- Don't forget to change the mode of blackfin serial driver to PIO.
- Otherwise kgdb works incorrectly on UART.
-
-4. If you want connect to kgdb when the kernel boots, enable
- "KGDB: Wait for gdb connection early"
-
-5. Connect minicom to the serial port and boot the kernel image.
-
-6. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A.
-
-7. Start GDB client "bfin-elf-gdb vmlinux".
-
-8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
-
-9. Connect to the target "(gdb) target remote /dev/ttyS0".
-
-10. Set software breakpoint "(gdb) break sys_open".
-
-11. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection.
-
-12. Run ls in the target console "/> ls". Dummy string can be seen on the console.
-
-13. Then connect the gdb to target again. "(gdb) target remote /dev/ttyS0".
- Now you will find a breakpoint is hit. "Breakpoint 1: sys_open(..."
-
-14. All other operations are the same as that in KGDB over Ethernet. The only
- difference is that after continue command in GDB, please stop GDB
- connection by 2 "Ctrl+C"s and connect again after breakpoints are hit or
- Ctrl+A is entered.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 3d2d0c29f02..cc8093c15cf 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -287,14 +287,6 @@ Who: Glauber Costa <gcosta@redhat.com>
---------------------------
-What: old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE)
-When: 2.6.28
-Why: This driver still uses the old interface and has been replaced
- by CONFIG_SERIAL_MCF.
-Who: Sebastian Siewior <sebastian@breakpoint.cc>
-
----------------------------
-
What: /sys/o2cb symlink
When: January 2010
Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 74484e69640..eb154ef36c2 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -223,6 +223,11 @@ errors=remount-ro(*) Remount the filesystem read-only on an error.
errors=continue Keep going on a filesystem error.
errors=panic Panic and halt the machine if an error occurs.
+data_err=ignore(*) Just print an error message if an error occurs
+ in a file data buffer in ordered mode.
+data_err=abort Abort the journal if an error occurs in a file
+ data buffer in ordered mode.
+
grpid Give objects the same group ID as their creator.
bsdgroups
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index d831d24d2a6..b488edad743 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1331,13 +1331,6 @@ determine whether or not they are still functioning properly.
Because the NMI watchdog shares registers with oprofile, by disabling the NMI
watchdog, oprofile may have more registers to utilize.
-maps_protect
-------------
-
-Enables/Disables the protection of the per-process proc entries "maps" and
-"smaps". When enabled, the contents of these files are visible only to
-readers that are allowed to ptrace() the given process.
-
msgmni
------
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 25efbaf1f59..2443f5bb436 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -658,11 +658,12 @@ and is between 256 and 4096 characters. It is defined in the file
earlyprintk= [X86-32,X86-64,SH,BLACKFIN]
earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]]
+ earlyprintk=dbgp
Append ",keep" to not disable it when the real console
takes over.
- Only vga or serial at a time, not both.
+ Only vga or serial or usb debug port at a time.
Currently only ttyS0 and ttyS1 are supported.
@@ -1231,6 +1232,29 @@ and is between 256 and 4096 characters. It is defined in the file
or
memmap=0x10000$0x18690000
+ memory_corruption_check=0/1 [X86]
+ Some BIOSes seem to corrupt the first 64k of
+ memory when doing things like suspend/resume.
+ Setting this option will scan the memory
+ looking for corruption. Enabling this will
+ both detect corruption and prevent the kernel
+ from using the memory being corrupted.
+ However, its intended as a diagnostic tool; if
+ repeatable BIOS-originated corruption always
+ affects the same memory, you can use memmap=
+ to prevent the kernel from using that memory.
+
+ memory_corruption_check_size=size [X86]
+ By default it checks for corruption in the low
+ 64k, making this memory unavailable for normal
+ use. Use this parameter to scan for
+ corruption in more or less memory.
+
+ memory_corruption_check_period=seconds [X86]
+ By default it checks for corruption every 60
+ seconds. Use this parameter to check at some
+ other rate. 0 disables periodic checking.
+
memtest= [KNL,X86] Enable memtest
Format: <integer>
range: 0,4 : pattern number
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index b54cb5048df..87a7c07ab65 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -5073,8 +5073,7 @@ struct _snd_pcm_runtime {
with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
<function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
where <constant>GFP_KERNEL</constant> is the kernel allocation flag to
- use. For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
- <function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
+ use.
For the PCI scatter-gather buffers, use
<constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
<function>snd_dma_pci_data(pci)</function>
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
deleted file mode 100644
index eb1e28ad882..00000000000
--- a/Documentation/sparc/sbus_drivers.txt
+++ /dev/null
@@ -1,309 +0,0 @@
-
- Writing SBUS Drivers
-
- David S. Miller (davem@redhat.com)
-
- The SBUS driver interfaces of the Linux kernel have been
-revamped completely for 2.4.x for several reasons. Foremost were
-performance and complexity concerns. This document details these
-new interfaces and how they are used to write an SBUS device driver.
-
- SBUS drivers need to include <asm/sbus.h> to get access
-to functions and structures described here.
-
- Probing and Detection
-
- Each SBUS device inside the machine is described by a
-structure called "struct sbus_dev". Likewise, each SBUS bus
-found in the system is described by a "struct sbus_bus". For
-each SBUS bus, the devices underneath are hung in a tree-like
-fashion off of the bus structure.
-
- The SBUS device structure contains enough information
-for you to implement your device probing algorithm and obtain
-the bits necessary to run your device. The most commonly
-used members of this structure, and their typical usage,
-will be detailed below.
-
- Here is a piece of skeleton code for performing a device
-probe in an SBUS driver under Linux:
-
- static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
- {
- struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-
- if (!mp)
- return -ENODEV;
-
- ...
- dev_set_drvdata(&sdev->ofdev.dev, mp);
- return 0;
- ...
- }
-
- static int __devinit mydevice_probe(struct of_device *dev,
- const struct of_device_id *match)
- {
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
- return mydevice_probe_one(sdev);
- }
-
- static int __devexit mydevice_remove(struct of_device *dev)
- {
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct mydevice *mp = dev_get_drvdata(&dev->dev);
-
- return mydevice_remove_one(sdev, mp);
- }
-
- static struct of_device_id mydevice_match[] = {
- {
- .name = "mydevice",
- },
- {},
- };
-
- MODULE_DEVICE_TABLE(of, mydevice_match);
-
- static struct of_platform_driver mydevice_driver = {
- .match_table = mydevice_match,
- .probe = mydevice_probe,
- .remove = __devexit_p(mydevice_remove),
- .driver = {
- .name = "mydevice",
- },
- };
-
- static int __init mydevice_init(void)
- {
- return of_register_driver(&mydevice_driver, &sbus_bus_type);
- }
-
- static void __exit mydevice_exit(void)
- {
- of_unregister_driver(&mydevice_driver);
- }
-
- module_init(mydevice_init);
- module_exit(mydevice_exit);
-
- The mydevice_match table is a series of entries which
-describes what SBUS devices your driver is meant for. In the
-simplest case you specify a string for the 'name' field. Every
-SBUS device with a 'name' property matching your string will
-be passed one-by-one to your .probe method.
-
- You should store away your device private state structure
-pointer in the drvdata area so that you can retrieve it later on
-in your .remove method.
-
- Any memory allocated, registers mapped, IRQs registered,
-etc. must be undone by your .remove method so that all resources
-of your device are released by the time it returns.
-
- You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
-and for_all_sbusdev() interfaces. They are deprecated, will be
-removed, and no new driver should reference them ever.
-
- Mapping and Accessing I/O Registers
-
- Each SBUS device structure contains an array of descriptors
-which describe each register set. We abuse struct resource for that.
-They each correspond to the "reg" properties provided by the OBP firmware.
-
- Before you can access your device's registers you must map
-them. And later if you wish to shutdown your driver (for module
-unload or similar) you must unmap them. You must treat them as
-a resource, which you allocate (map) before using and free up
-(unmap) when you are done with it.
-
- The mapping information is stored in an opaque value
-typed as an "unsigned long". This is the type of the return value
-of the mapping interface, and the arguments to the unmapping
-interface. Let's say you want to map the first set of registers.
-Perhaps part of your driver software state structure looks like:
-
- struct mydevice {
- unsigned long control_regs;
- ...
- struct sbus_dev *sdev;
- ...
- };
-
- At initialization time you then use the sbus_ioremap
-interface to map in your registers, like so:
-
- static void init_one_mydevice(struct sbus_dev *sdev)
- {
- struct mydevice *mp;
- ...
-
- mp->control_regs = sbus_ioremap(&sdev->resource[0], 0,
- CONTROL_REGS_SIZE, "mydevice regs");
- if (!mp->control_regs) {
- /* Failure, cleanup and return. */
- }
- }
-
- Second argument to sbus_ioremap is an offset for
-cranky devices with broken OBP PROM. The sbus_ioremap uses only
-a start address and flags from the resource structure.
-Therefore it is possible to use the same resource to map
-several sets of registers or even to fabricate a resource
-structure if driver gets physical address from some private place.
-This practice is discouraged though. Use whatever OBP PROM
-provided to you.
-
- And here is how you might unmap these registers later at
-driver shutdown or module unload time, using the sbus_iounmap
-interface:
-
- static void mydevice_unmap_regs(struct mydevice *mp)
- {
- sbus_iounmap(mp->control_regs, CONTROL_REGS_SIZE);
- }
-
- Finally, to actually access your registers there are 6
-interface routines at your disposal. Accesses are byte (8 bit),
-word (16 bit), or longword (32 bit) sized. Here they are:
-
- u8 sbus_readb(unsigned long reg) /* read byte */
- u16 sbus_readw(unsigned long reg) /* read word */
- u32 sbus_readl(unsigned long reg) /* read longword */
- void sbus_writeb(u8 value, unsigned long reg) /* write byte */
- void sbus_writew(u16 value, unsigned long reg) /* write word */
- void sbus_writel(u32 value, unsigned long reg) /* write longword */
-
- So, let's say your device has a control register of some sort
-at offset zero. The following might implement resetting your device:
-
- #define CONTROL 0x00UL
-
- #define CONTROL_RESET 0x00000001 /* Reset hardware */
-
- static void mydevice_reset(struct mydevice *mp)
- {
- sbus_writel(CONTROL_RESET, mp->regs + CONTROL);
- }
-
- Or perhaps there is a data port register at an offset of
-16 bytes which allows you to read bytes from a fifo in the device:
-
- #define DATA 0x10UL
-
- static u8 mydevice_get_byte(struct mydevice *mp)
- {
- return sbus_readb(mp->regs + DATA);
- }
-
- It's pretty straightforward, and clueful readers may have
-noticed that these interfaces mimick the PCI interfaces of the
-Linux kernel. This was not by accident.
-
- WARNING:
-
- DO NOT try to treat these opaque register mapping
- values as a memory mapped pointer to some structure
- which you can dereference.
-
- It may be memory mapped, it may not be. In fact it
- could be a physical address, or it could be the time
- of day xor'd with 0xdeadbeef. :-)
-
- Whatever it is, it's an implementation detail. The
- interface was done this way to shield the driver
- author from such complexities.
-
- Doing DVMA
-
- SBUS devices can perform DMA transactions in a way similar
-to PCI but dissimilar to ISA, e.g. DMA masters supply address.
-In contrast to PCI, however, that address (a bus address) is
-translated by IOMMU before a memory access is performed and therefore
-it is virtual. Sun calls this procedure DVMA.
-
- Linux supports two styles of using SBUS DVMA: "consistent memory"
-and "streaming DVMA". CPU view of consistent memory chunk is, well,
-consistent with a view of a device. Think of it as an uncached memory.
-Typically this way of doing DVMA is not very fast and drivers use it
-mostly for control blocks or queues. On some CPUs we cannot flush or
-invalidate individual pages or cache lines and doing explicit flushing
-over ever little byte in every control block would be wasteful.
-
-Streaming DVMA is a preferred way to transfer large amounts of data.
-This process works in the following way:
-1. a CPU stops accessing a certain part of memory,
- flushes its caches covering that memory;
-2. a device does DVMA accesses, then posts an interrupt;
-3. CPU invalidates its caches and starts to access the memory.
-
-A single streaming DVMA operation can touch several discontiguous
-regions of a virtual bus address space. This is called a scatter-gather
-DVMA.
-
-[TBD: Why do not we neither Solaris attempt to map disjoint pages
-into a single virtual chunk with the help of IOMMU, so that non SG
-DVMA masters would do SG? It'd be very helpful for RAID.]
-
- In order to perform a consistent DVMA a driver does something
-like the following:
-
- char *mem; /* Address in the CPU space */
- u32 busa; /* Address in the SBus space */
-
- mem = (char *) sbus_alloc_consistent(sdev, MYMEMSIZE, &busa);
-
- Then mem is used when CPU accesses this memory and u32
-is fed to the device so that it can do DVMA. This is typically
-done with an sbus_writel() into some device register.
-
- Do not forget to free the DVMA resources once you are done:
-
- sbus_free_consistent(sdev, MYMEMSIZE, mem, busa);
-
- Streaming DVMA is more interesting. First you allocate some
-memory suitable for it or pin down some user pages. Then it all works
-like this:
-
- char *mem = argumen1;
- unsigned int size = argument2;
- u32 busa; /* Address in the SBus space */
-
- *mem = 1; /* CPU can access */
- busa = sbus_map_single(sdev, mem, size);
- if (busa == 0) .......
-
- /* Tell the device to use busa here */
- /* CPU cannot access the memory without sbus_dma_sync_single() */
-
- sbus_unmap_single(sdev, busa, size);
- if (*mem == 0) .... /* CPU can access again */
-
- It is possible to retain mappings and ask the device to
-access data again and again without calling sbus_unmap_single.
-However, CPU caches must be invalidated with sbus_dma_sync_single
-before such access.
-
-[TBD but what about writeback caches here... do we have any?]
-
- There is an equivalent set of functions doing the same thing
-only with several memory segments at once for devices capable of
-scatter-gather transfers. Use the Source, Luke.
-
- Examples
-
- drivers/net/sunhme.c
- This is a complicated driver which illustrates many concepts
-discussed above and plus it handles both PCI and SBUS boards.
-
- drivers/scsi/esp.c
- Check it out for scatter-gather DVMA.
-
- drivers/sbus/char/bpp.c
- A non-DVMA device.
-
- drivers/net/sunlance.c
- Lance driver abuses consistent mappings for data transfer.
-It is a nifty trick which we do not particularly recommend...
-Just check it out and know that it's legal.
diff --git a/Documentation/timers/00-INDEX b/Documentation/timers/00-INDEX
new file mode 100644
index 00000000000..397dc35e132
--- /dev/null
+++ b/Documentation/timers/00-INDEX
@@ -0,0 +1,10 @@
+00-INDEX
+ - this file
+highres.txt
+ - High resolution timers and dynamic ticks design notes
+hpet.txt
+ - High Precision Event Timer Driver for Linux
+hrtimers.txt
+ - subsystem for high-resolution kernel timers
+timer_stats.txt
+ - timer usage statistics
diff --git a/Documentation/hpet.txt b/Documentation/timers/hpet.txt
index 6ad52d9dad6..e7c09abcfab 100644
--- a/Documentation/hpet.txt
+++ b/Documentation/timers/hpet.txt
@@ -1,21 +1,32 @@
High Precision Event Timer Driver for Linux
-The High Precision Event Timer (HPET) hardware is the future replacement
-for the 8254 and Real Time Clock (RTC) periodic timer functionality.
-Each HPET can have up to 32 timers. It is possible to configure the
-first two timers as legacy replacements for 8254 and RTC periodic timers.
-A specification done by Intel and Microsoft can be found at
-<http://www.intel.com/technology/architecture/hpetspec.htm>.
+The High Precision Event Timer (HPET) hardware follows a specification
+by Intel and Microsoft which can be found at
+
+ http://www.intel.com/technology/architecture/hpetspec.htm
+
+Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
+and up to 32 comparators. Normally three or more comparators are provided,
+each of which can generate oneshot interupts and at least one of which has
+additional hardware to support periodic interrupts. The comparators are
+also called "timers", which can be misleading since usually timers are
+independent of each other ... these share a counter, complicating resets.
+
+HPET devices can support two interrupt routing modes. In one mode, the
+comparators are additional interrupt sources with no particular system
+role. Many x86 BIOS writers don't route HPET interrupts at all, which
+prevents use of that mode. They support the other "legacy replacement"
+mode where the first two comparators block interrupts from 8254 timers
+and from the RTC.
The driver supports detection of HPET driver allocation and initialization
of the HPET before the driver module_init routine is called. This enables
platform code which uses timer 0 or 1 as the main timer to intercept HPET
initialization. An example of this initialization can be found in
-arch/i386/kernel/time_hpet.c.
+arch/x86/kernel/hpet.c.
-The driver provides two APIs which are very similar to the API found in
-the rtc.c driver. There is a user space API and a kernel space API.
-An example user space program is provided below.
+The driver provides a userspace API which resembles the API found in the
+RTC driver framework. An example user space program is provided below.
#include <stdio.h>
#include <stdlib.h>
@@ -286,15 +297,3 @@ out:
return;
}
-
-The kernel API has three interfaces exported from the driver:
-
- hpet_register(struct hpet_task *tp, int periodic)
- hpet_unregister(struct hpet_task *tp)
- hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
-
-The kernel module using this interface fills in the ht_func and ht_data
-members of the hpet_task structure before calling hpet_register.
-hpet_control simply vectors to the hpet_ioctl routine and has the same
-commands and respective arguments as the user API. hpet_unregister
-is used to terminate usage of the HPET timer reserved by hpet_register.
diff --git a/MAINTAINERS b/MAINTAINERS
index 587f418ed00..988b0a85289 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -72,6 +72,7 @@ M: Mail patches to
L: Mailing list that is relevant to this area
W: Web-page with status/info
T: SCM tree type and location. Type is one of: git, hg, quilt.
+F: Applicable files and/or directories
S: Status, one of the following:
Supported: Someone is actually paid to look after this.
@@ -102,14 +103,14 @@ M: dave@thedillows.org
L: netdev@vger.kernel.org
S: Maintained
-3W-XXXX ATA-RAID CONTROLLER DRIVER
+3W-9XXX SATA-RAID CONTROLLER DRIVER
P: Adam Radford
M: linuxraid@amcc.com
L: linux-scsi@vger.kernel.org
W: http://www.amcc.com
S: Supported
-3W-9XXX SATA-RAID CONTROLLER DRIVER
+3W-XXXX ATA-RAID CONTROLLER DRIVER
P: Adam Radford
M: linuxraid@amcc.com
L: linux-scsi@vger.kernel.org
@@ -163,16 +164,11 @@ M: A2232@gmx.net
L: linux-m68k@lists.linux-m68k.org
S: Maintained
-AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
-P: David Howells
-M: dhowells@redhat.com
-L: linux-afs@lists.infradead.org
-S: Supported
-
-AIO
-P: Benjamin LaHaise
-M: bcrl@kvack.org
-L: linux-aio@kvack.org
+AACRAID SCSI RAID DRIVER
+P: Adaptec OEM Raid Solutions
+M: aacraid@adaptec.com
+L: linux-scsi@vger.kernel.org
+W: http://www.adaptec.com/
S: Supported
ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
@@ -193,27 +189,6 @@ M: jes@trained-monkey.org
L: linux-acenic@sunsite.dk
S: Maintained
-IPS SCSI RAID DRIVER
-P: Adaptec OEM Raid Solutions
-M: aacraid@adaptec.com
-L: linux-scsi@vger.kernel.org
-W: http://www.adaptec.com/
-S: Maintained
-
-DPT_I2O SCSI RAID DRIVER
-P: Adaptec OEM Raid Solutions
-M: aacraid@adaptec.com
-L: linux-scsi@vger.kernel.org
-W: http://www.adaptec.com/
-S: Maintained
-
-AACRAID SCSI RAID DRIVER
-P: Adaptec OEM Raid Solutions
-M: aacraid@adaptec.com
-L: linux-scsi@vger.kernel.org
-W: http://www.adaptec.com/
-S: Supported
-
ACER WMI LAPTOP EXTRAS
P: Carlos Corbacho
M: carlos@strangeworlds.co.uk
@@ -327,6 +302,12 @@ P: Roman Zippel
M: zippel@linux-m68k.org
S: Maintained
+AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
+P: David Howells
+M: dhowells@redhat.com
+L: linux-afs@lists.infradead.org
+S: Supported
+
AGPGART DRIVER
P: David Airlie
M: airlied@linux.ie
@@ -345,6 +326,12 @@ M: hare@suse.de
L: linux-scsi@vger.kernel.org
S: Maintained
+AIO
+P: Benjamin LaHaise
+M: bcrl@kvack.org
+L: linux-aio@kvack.org
+S: Supported
+
ALCATEL SPEEDTOUCH USB DRIVER
P: Duncan Sands
M: duncan.sands@free.fr
@@ -390,6 +377,11 @@ L: iommu@lists.linux-foundation.org
T: git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
S: Supported
+AMD MICROCODE UPDATE SUPPORT
+P: Peter Oruba
+M: peter.oruba@amd.com
+S: Supported
+
AMS (Apple Motion Sensor) DRIVER
P: Stelian Pop
M: stelian@popies.net
@@ -732,7 +724,7 @@ L: linux-kernel@vger.kernel.org
W: http://sourceforge.net/projects/xscaleiop
S: Supported
-ATA OVER ETHERNET DRIVER
+ATA OVER ETHERNET (AOE) DRIVER
P: Ed L. Cashin
M: ecashin@coraid.com
W: http://www.coraid.com/support/linux
@@ -865,11 +857,48 @@ L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
+B43 WIRELESS DRIVER
+P: Michael Buesch
+M: mb@bu3sch.de
+P: Stefano Brivio
+M: stefano.brivio@polimi.it
+L: linux-wireless@vger.kernel.org
+W: http://linuxwireless.org/en/users/Drivers/b43
+S: Maintained
+
+B43LEGACY WIRELESS DRIVER
+P: Larry Finger
+M: Larry.Finger@lwfinger.net
+P: Stefano Brivio
+M: stefano.brivio@polimi.it
+L: linux-wireless@vger.kernel.org
+W: http://linuxwireless.org/en/users/Drivers/b43
+S: Maintained
+
BACKLIGHT CLASS/SUBSYSTEM
P: Richard Purdie
M: rpurdie@rpsys.net
S: Maintained
+BAYCOM/HDLCDRV DRIVERS FOR AX.25
+P: Thomas Sailer
+M: t.sailer@alumni.ethz.ch
+L: linux-hams@vger.kernel.org
+W: http://www.baycom.org/~tom/ham/ham.html
+S: Maintained
+
+BEFS FILE SYSTEM
+P: Sergey S. Kostyliov
+M: rathamahata@php4.ru
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
+BFS FILE SYSTEM
+P: Tigran A. Aivazian
+M: tigran@aivazian.fsnet.co.uk
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
BLACKFIN ARCHITECTURE
P: Bryan Wu
M: cooloney@kernel.org
@@ -905,43 +934,6 @@ L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
W: http://blackfin.uclinux.org
S: Supported
-BAYCOM/HDLCDRV DRIVERS FOR AX.25
-P: Thomas Sailer
-M: t.sailer@alumni.ethz.ch
-L: linux-hams@vger.kernel.org
-W: http://www.baycom.org/~tom/ham/ham.html
-S: Maintained
-
-B43 WIRELESS DRIVER
-P: Michael Buesch
-M: mb@bu3sch.de
-P: Stefano Brivio
-M: stefano.brivio@polimi.it
-L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/en/users/Drivers/b43
-S: Maintained
-
-B43LEGACY WIRELESS DRIVER
-P: Larry Finger
-M: Larry.Finger@lwfinger.net
-P: Stefano Brivio
-M: stefano.brivio@polimi.it
-L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/en/users/Drivers/b43
-S: Maintained
-
-BEFS FILE SYSTEM
-P: Sergey S. Kostyliov
-M: rathamahata@php4.ru
-L: linux-kernel@vger.kernel.org
-S: Maintained
-
-BFS FILE SYSTEM
-P: Tigran A. Aivazian
-M: tigran@aivazian.fsnet.co.uk
-L: linux-kernel@vger.kernel.org
-S: Maintained
-
BLACKFIN I2C TWI DRIVER
P: Sonic Zhang
M: sonic.zhang@analog.com
@@ -1035,15 +1027,6 @@ M: corbet@lwn.net
L: video4linux-list@redhat.com
S: Maintained
-CAN NETWORK LAYER
-P: Urs Thuermann
-M: urs.thuermann@volkswagen.de
-P: Oliver Hartkopp
-M: oliver.hartkopp@volkswagen.de
-L: socketcan-core@lists.berlios.de (subscribers-only)
-W: http://developer.berlios.de/projects/socketcan/
-S: Maintained
-
CALGARY x86-64 IOMMU
P: Muli Ben-Yehuda
M: muli@il.ibm.com
@@ -1053,6 +1036,15 @@ L: linux-kernel@vger.kernel.org
L: discuss@x86-64.org
S: Maintained
+CAN NETWORK LAYER
+P: Urs Thuermann
+M: urs.thuermann@volkswagen.de
+P: Oliver Hartkopp
+M: oliver.hartkopp@volkswagen.de
+L: socketcan-core@lists.berlios.de (subscribers-only)
+W: http://developer.berlios.de/projects/socketcan/
+S: Maintained
+
CELL BROADBAND ENGINE ARCHITECTURE
P: Arnd Bergmann
M: arnd@arndb.de
@@ -1061,13 +1053,6 @@ L: cbe-oss-dev@ozlabs.org
W: http://www.ibm.com/developerworks/power/cell/
S: Supported
-CISCO 10G ETHERNET DRIVER
-P: Scott Feldman
-M: scofeldm@cisco.com
-P: Joe Eykholt
-M: jeykholt@cisco.com
-S: Supported
-
CFAG12864B LCD DRIVER
P: Miguel Ojeda Sandonis
M: miguel.ojeda.sandonis@gmail.com
@@ -1099,19 +1084,11 @@ P: Joel Schopp
M: jschopp@austin.ibm.com
S: Supported
-COMMON INTERNET FILE SYSTEM (CIFS)
-P: Steve French
-M: sfrench@samba.org
-L: linux-cifs-client@lists.samba.org
-L: samba-technical@lists.samba.org
-W: http://linux-cifs.samba.org/
-T: git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
-S: Supported
-
-CONFIGFS
-P: Joel Becker
-M: joel.becker@oracle.com
-L: linux-kernel@vger.kernel.org
+CISCO 10G ETHERNET DRIVER
+P: Scott Feldman
+M: scofeldm@cisco.com
+P: Joe Eykholt
+M: jeykholt@cisco.com
S: Supported
CIRRUS LOGIC EP93XX ETHERNET DRIVER
@@ -1147,6 +1124,15 @@ L: codalist@coda.cs.cmu.edu
W: http://www.coda.cs.cmu.edu/
S: Maintained
+COMMON INTERNET FILE SYSTEM (CIFS)
+P: Steve French
+M: sfrench@samba.org
+L: linux-cifs-client@lists.samba.org
+L: samba-technical@lists.samba.org
+W: http://linux-cifs.samba.org/
+T: git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
+S: Supported
+
COMPACTPCI HOTPLUG CORE
P: Scott Murray
M: scottm@somanetworks.com
@@ -1186,6 +1172,12 @@ L: accessrunner-general@lists.sourceforge.net
W: http://accessrunner.sourceforge.net/
S: Maintained
+CONFIGFS
+P: Joel Becker
+M: joel.becker@oracle.com
+L: linux-kernel@vger.kernel.org
+S: Supported
+
CONTROL GROUPS (CGROUPS)
P: Paul Menage
M: menage@google.com
@@ -1309,6 +1301,20 @@ W: http://www.qsl.net/dl1bke/
L: linux-hams@vger.kernel.org
S: Maintained
+DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
+P: Tobias Ringstrom
+M: tori@unhappy.mine.nu
+L: netdev@vger.kernel.org
+S: Maintained
+
+DC390/AM53C974 SCSI driver
+P: Kurt Garloff
+M: garloff@suse.de
+W: http://www.garloff.de/kurt/linux/dc390/
+P: Guennadi Liakhovetski
+M: g.liakhovetski@gmx.de
+S: Maintained
+
DC395x SCSI driver
P: Oliver Neukum
M: oliver@neukum.name
@@ -1321,14 +1327,6 @@ L: dc395x@twibble.org
L: http://lists.twibble.org/mailman/listinfo/dc395x/
S: Maintained
-DC390/AM53C974 SCSI driver
-P: Kurt Garloff
-M: garloff@suse.de
-W: http://www.garloff.de/kurt/linux/dc390/
-P: Guennadi Liakhovetski
-M: g.liakhovetski@gmx.de
-S: Maintained
-
DCCP PROTOCOL
P: Arnaldo Carvalho de Melo
M: acme@ghostprotocols.net
@@ -1359,12 +1357,6 @@ P: Doug Warzecha
M: Douglas_Warzecha@dell.com
S: Maintained
-DEVICE-MAPPER (LVM)
-P: Alasdair Kergon
-L: dm-devel@redhat.com
-W: http://sources.redhat.com/dm
-S: Maintained
-
DEVICE NUMBER REGISTRY
P: Torben Mathiasen
M: device@lanana.org
@@ -1372,6 +1364,12 @@ W: http://lanana.org/docs/device-list/index.html
L: linux-kernel@vger.kernel.org
S: Maintained
+DEVICE-MAPPER (LVM)
+P: Alasdair Kergon
+L: dm-devel@redhat.com
+W: http://sources.redhat.com/dm
+S: Maintained
+
DIGI INTL. EPCA DRIVER
P: Digi International, Inc
M: Eng.Linux@digi.com
@@ -1379,7 +1377,7 @@ L: Eng.Linux@digi.com
W: http://www.digi.com
S: Orphan
-DIRECTORY NOTIFICATION
+DIRECTORY NOTIFICATION (DNOTIFY)
P: Stephen Rothwell
M: sfr@canb.auug.org.au
L: linux-kernel@vger.kernel.org
@@ -1393,13 +1391,13 @@ W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
S: Maintained
-DISKQUOTA:
+DISKQUOTA
P: Jan Kara
M: jack@suse.cz
L: linux-kernel@vger.kernel.org
S: Maintained
-DISTRIBUTED LOCK MANAGER
+DISTRIBUTED LOCK MANAGER (DLM)
P: Christine Caulfield
M: ccaulfie@redhat.com
P: David Teigland
@@ -1409,12 +1407,6 @@ W: http://sources.redhat.com/cluster/
T: git kernel.org:/pub/scm/linux/kernel/git/teigland/dlm.git
S: Supported
-DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
-P: Tobias Ringstrom
-M: tori@unhappy.mine.nu
-L: netdev@vger.kernel.org
-S: Maintained
-
DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
P: Maciej Sosnowski
M: maciej.sosnowski@intel.com
@@ -1454,6 +1446,13 @@ M: jrv@vanzandt.mv.com
L: blinux-list@redhat.com
S: Maintained
+DPT_I2O SCSI RAID DRIVER
+P: Adaptec OEM Raid Solutions
+M: aacraid@adaptec.com
+L: linux-scsi@vger.kernel.org
+W: http://www.adaptec.com/
+S: Maintained
+
DRIVER CORE, KOBJECTS, AND SYSFS
P: Greg Kroah-Hartman
M: gregkh@suse.de
@@ -1602,7 +1601,7 @@ EFS FILESYSTEM
W: http://aeschi.ch.eu.org/efs/
S: Orphan
-EHCA (IBM GX bus InfiniBand adapter) DRIVER:
+EHCA (IBM GX bus InfiniBand adapter) DRIVER
P: Hoang-Nam Nguyen
M: hnguyen@de.ibm.com
P: Christoph Raisch
@@ -1682,6 +1681,42 @@ P: Akinobu Mita
M: akinobu.mita@gmail.com
S: Supported
+FILE LOCKING (flock() and fcntl()/lockf())
+P: Matthew Wilcox
+M: matthew@wil.cx
+L: linux-fsdevel@vger.kernel.org
+S: Maintained
+
+FILESYSTEMS (VFS and infrastructure)
+P: Alexander Viro
+M: viro@zeniv.linux.org.uk
+L: linux-fsdevel@vger.kernel.org
+S: Maintained
+
+FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
+P: Kristian Hoegsberg, Stefan Richter
+M: krh@redhat.com, stefanr@s5r6.in-berlin.de
+L: linux1394-devel@lists.sourceforge.net
+W: http://www.linux1394.org/
+T: git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
+S: Maintained
+
+FIRMWARE LOADER (request_firmware)
+L: linux-kernel@vger.kernel.org
+S: Orphan
+
+FPU EMULATOR
+P: Bill Metzenthen
+M: billm@suburbia.net
+W: http://suburbia.net/~billm/floating-point/emulator/
+S: Maintained
+
+FRAME RELAY DLCI/FRAD (Sangoma drivers too)
+P: Mike McLagan
+M: mike.mclagan@linux.org
+L: netdev@vger.kernel.org
+S: Maintained
+
FRAMEBUFFER LAYER
P: Antonino Daplas
M: adaplas@gmail.com
@@ -1747,42 +1782,6 @@ L: alsa-devel@alsa-project.org
L: linuxppc-dev@ozlabs.org
S: Supported
-FILE LOCKING (flock() and fcntl()/lockf())
-P: Matthew Wilcox
-M: matthew@wil.cx
-L: linux-fsdevel@vger.kernel.org
-S: Maintained
-
-FILESYSTEMS (VFS and infrastructure)
-P: Alexander Viro
-M: viro@zeniv.linux.org.uk
-L: linux-fsdevel@vger.kernel.org
-S: Maintained
-
-FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
-P: Kristian Hoegsberg, Stefan Richter
-M: krh@redhat.com, stefanr@s5r6.in-berlin.de
-L: linux1394-devel@lists.sourceforge.net
-W: http://www.linux1394.org/
-T: git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
-S: Maintained
-
-FIRMWARE LOADER (request_firmware)
-L: linux-kernel@vger.kernel.org
-S: Orphan
-
-FPU EMULATOR
-P: Bill Metzenthen
-M: billm@suburbia.net
-W: http://suburbia.net/~billm/floating-point/emulator/
-S: Maintained
-
-FRAME RELAY DLCI/FRAD (Sangoma drivers too)
-P: Mike McLagan
-M: mike.mclagan@linux.org
-L: netdev@vger.kernel.org
-S: Maintained
-
FREEVXFS FILESYSTEM
P: Christoph Hellwig
M: hch@infradead.org
@@ -1854,6 +1853,13 @@ L: gigaset307x-common@lists.sourceforge.net
W: http://gigaset307x.sourceforge.net/
S: Maintained
+HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
+P: Robert Love
+M: rlove@rlove.org
+M: linux-kernel@vger.kernel.org
+W: http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
+S: Maintained
+
HARDWARE MONITORING
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/
@@ -1862,13 +1868,6 @@ S: Orphan
HARDWARE RANDOM NUMBER GENERATOR CORE
S: Orphan
-HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
-P: Robert Love
-M: rlove@rlove.org
-M: linux-kernel@vger.kernel.org
-W: http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
-S: Maintained
-
HARMONY SOUND DRIVER
P: Kyle McMartin
M: kyle@mcmartin.ca
@@ -1882,6 +1881,24 @@ L: linux-kernel@vger.kernel.org
W: http://www.nyx.net/~arobinso
S: Maintained
+HEWLETT-PACKARD FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
+P: Chirag Kantharia
+M: chirag.kantharia@hp.com
+L: iss_storagedev@hp.com
+S: Maintained
+
+HEWLETT-PACKARD SMART2 RAID DRIVER
+P: Chirag Kantharia
+M: chirag.kantharia@hp.com
+L: iss_storagedev@hp.com
+S: Maintained
+
+HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
+P: Mike Miller
+M: mike.miller@hp.com
+L: iss_storagedev@hp.com
+S: Supported
+
HFS FILESYSTEM
P: Roman Zippel
M: zippel@linux-m68k.org
@@ -1895,6 +1912,14 @@ L: linux-nvidia@lists.surfsouth.com
W: http://drama.obuda.kando.hu/~fero/cgi-bin/hgafb.shtml
S: Maintained
+HIBERNATION (aka Software Suspend, aka swsusp)
+P: Pavel Machek
+M: pavel@suse.cz
+P: Rafael J. Wysocki
+M: rjw@sisk.pl
+L: linux-pm@lists.linux-foundation.org
+S: Supported
+
HID CORE LAYER
P: Jiri Kosina
M: jkosina@suse.cz
@@ -1927,24 +1952,6 @@ M: jes@trained-monkey.org
L: linux-hippi@sunsite.dk
S: Maintained
-HEWLETT-PACKARD FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
-P: Chirag Kantharia
-M: chirag.kantharia@hp.com
-L: iss_storagedev@hp.com
-S: Maintained
-
-HEWLETT-PACKARD SMART2 RAID DRIVER
-P: Chirag Kantharia
-M: chirag.kantharia@hp.com
-L: iss_storagedev@hp.com
-S: Maintained
-
-HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
-P: Mike Miller
-M: mike.miller@hp.com
-L: iss_storagedev@hp.com
-S: Supported
-
HOST AP DRIVER
P: Jouni Malinen
M: j@w1.fi
@@ -1953,16 +1960,16 @@ L: linux-wireless@vger.kernel.org
W: http://hostap.epitest.fi/
S: Maintained
-HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
-P: Jaroslav Kysela
-M: perex@perex.cz
-S: Maintained
-
HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
P: Carlos Corbacho
M: carlos@strangeworlds.co.uk
S: Odd Fixes
+HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
+P: Jaroslav Kysela
+M: perex@perex.cz
+S: Maintained
+
HPET: High Precision Event Timers driver (drivers/char/hpet.c)
P: Clemens Ladisch
M: clemens@ladisch.de
@@ -2042,14 +2049,6 @@ W: http://www.ia64-linux.org/
T: git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
S: Maintained
-SN-IA64 (Itanium) SUB-PLATFORM
-P: Jes Sorensen
-M: jes@sgi.com
-L: linux-altix@sgi.com
-L: linux-ia64@vger.kernel.org
-W: http://www.sgi.com/altix
-S: Maintained
-
IBM MCA SCSI SUBSYSTEM DRIVER
P: Michael Lang
M: langa2@kph.uni-mainz.de
@@ -2133,14 +2132,6 @@ W: http://www.openib.org/
T: git kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
S: Supported
-INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
-P: Dmitry Torokhov
-M: dmitry.torokhov@gmail.com
-M: dtor@mail.ru
-L: linux-input@vger.kernel.org
-T: git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
-S: Maintained
-
INOTIFY
P: John McCutchan
M: ttb@tentacle.dhs.org
@@ -2149,6 +2140,14 @@ M: rml@novell.com
L: linux-kernel@vger.kernel.org
S: Maintained
+INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
+P: Dmitry Torokhov
+M: dmitry.torokhov@gmail.com
+M: dtor@mail.ru
+L: linux-input@vger.kernel.org
+T: git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
+S: Maintained
+
INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
P: Sylvain Meyer
M: sylvain.meyer@worldonline.fr
@@ -2253,7 +2252,7 @@ M: pfg@sgi.com
L: linux-mips@linux-mips.org
S: Maintained
-IP MASQUERADING:
+IP MASQUERADING
P: Juanjo Ciarlante
M: jjciarla@raiz.uncu.edu.ar
S: Maintained
@@ -2268,7 +2267,7 @@ M: jesse@icplus.com.tw
L: netdev@vger.kernel.org
S: Maintained
-IPATH DRIVER:
+IPATH DRIVER
P: Ralph Campbell
M: infinipath@qlogic.com
L: general@lists.openfabrics.org
@@ -2282,13 +2281,25 @@ L: openipmi-developer@lists.sourceforge.net
W: http://openipmi.sourceforge.net/
S: Supported
-IPX NETWORK LAYER
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
+IPS SCSI RAID DRIVER
+P: Adaptec OEM Raid Solutions
+M: aacraid@adaptec.com
+L: linux-scsi@vger.kernel.org
+W: http://www.adaptec.com/
+S: Maintained
+
+IPVS
+P: Wensong Zhang
+M: wensong@linux-vs.org
+P: Simon Horman
+M: horms@verge.net.au
+P: Julian Anastasov
+M: ja@ssi.bg
L: netdev@vger.kernel.org
+L: lvs-devel@vger.kernel.org
S: Maintained
-IPWIRELES DRIVER
+IPWIRELESS DRIVER
P: Jiri Kosina
M: jkosina@suse.cz
P: David Sterba
@@ -2296,6 +2307,12 @@ M: dsterba@suse.cz
S: Maintained
T: git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git
+IPX NETWORK LAYER
+P: Arnaldo Carvalho de Melo
+M: acme@ghostprotocols.net
+L: netdev@vger.kernel.org
+S: Maintained
+
IRDA SUBSYSTEM
P: Samuel Ortiz
M: samuel@sortiz.org
@@ -2303,6 +2320,11 @@ L: irda-users@lists.sourceforge.net (subscribers-only)
W: http://irda.sourceforge.net/
S: Maintained
+ISAPNP
+P: Jaroslav Kysela
+M: perex@perex.cz
+S: Maintained
+
ISCSI
P: Mike Christie
M: michaelc@cs.wisc.edu
@@ -2311,11 +2333,6 @@ W: www.open-iscsi.org
T: git kernel.org:/pub/scm/linux/kernel/mnc/linux-2.6-iscsi.git
S: Maintained
-ISAPNP
-P: Jaroslav Kysela
-M: perex@perex.cz
-S: Maintained
-
ISDN SUBSYSTEM
P: Karsten Keil
M: kkeil@suse.de
@@ -2340,6 +2357,14 @@ L: video4linux-list@redhat.com
W: http://www.ivtvdriver.org
S: Maintained
+JFS FILESYSTEM
+P: Dave Kleikamp
+M: shaggy@austin.ibm.com
+L: jfs-discussion@lists.sourceforge.net
+W: http://jfs.sourceforge.net/
+T: git kernel.org:/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
+S: Supported
+
JME NETWORK DRIVER
P: Guo-Fu Tseng
M: cooldavid@cooldavid.org
@@ -2353,24 +2378,6 @@ L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/doc/jffs2.html
S: Maintained
-UBI FILE SYSTEM (UBIFS)
-P: Artem Bityutskiy
-M: dedekind@infradead.org
-P: Adrian Hunter
-M: ext-adrian.hunter@nokia.com
-L: linux-mtd@lists.infradead.org
-T: git git://git.infradead.org/~dedekind/ubifs-2.6.git
-W: http://www.linux-mtd.infradead.org/doc/ubifs.html
-S: Maintained
-
-JFS FILESYSTEM
-P: Dave Kleikamp
-M: shaggy@austin.ibm.com
-L: jfs-discussion@lists.sourceforge.net
-W: http://jfs.sourceforge.net/
-T: git kernel.org:/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
-S: Supported
-
JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
P: Stephen Tweedie, Andrew Morton
M: sct@redhat.com, akpm@linux-foundation.org
@@ -2607,11 +2614,6 @@ W: http://www.pasemi.com/
L: linuxppc-dev@ozlabs.org
S: Supported
-LLC (802.2)
-P: Arnaldo Carvalho de Melo
-M: acme@ghostprotocols.net
-S: Maintained
-
LINUX SECURITY MODULE (LSM) FRAMEWORK
P: Chris Wright
M: chrisw@sous-sol.org
@@ -2619,6 +2621,11 @@ L: linux-security-module@vger.kernel.org
T: git kernel.org:/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
S: Supported
+LLC (802.2)
+P: Arnaldo Carvalho de Melo
+M: acme@ghostprotocols.net
+S: Maintained
+
LM83 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
@@ -2719,14 +2726,6 @@ M: kaber@trash.net
L: netdev@vger.kernel.org
S: Maintained
-MARVELL YUKON / SYSKONNECT DRIVER
-P: Mirko Lindner
-M: mlindner@syskonnect.de
-P: Ralph Roesler
-M: rroesler@syskonnect.de
-W: http://www.syskonnect.com
-S: Supported
-
MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
P: Michael Kerrisk
M: mtk.manpages@gmail.com
@@ -2746,6 +2745,14 @@ M: buytenh@marvell.com
L: netdev@vger.kernel.org
S: Supported
+MARVELL YUKON / SYSKONNECT DRIVER
+P: Mirko Lindner
+M: mlindner@syskonnect.de
+P: Ralph Roesler
+M: rroesler@syskonnect.de
+W: http://www.syskonnect.com
+S: Supported
+
MATROX FRAMEBUFFER DRIVER
P: Petr Vandrovec
M: vandrove@vc.cvut.cz
@@ -2782,15 +2789,6 @@ L: linux-mm@kvack.org
L: linux-kernel@vger.kernel.org
S: Maintained
-MEI MN10300/AM33 PORT
-P: David Howells
-M: dhowells@redhat.com
-P: Koichi Yasutake
-M: yasutake.koichi@jp.panasonic.com
-L: linux-am33-list@redhat.com (moderated for non-subscribers)
-W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
-S: Maintained
-
MEMORY TECHNOLOGY DEVICES (MTD)
P: David Woodhouse
M: dwmw2@infradead.org
@@ -2799,14 +2797,6 @@ L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/mtd-2.6.git
S: Maintained
-UNSORTED BLOCK IMAGES (UBI)
-P: Artem Bityutskiy
-M: dedekind@infradead.org
-W: http://www.linux-mtd.infradead.org/
-L: linux-mtd@lists.infradead.org
-T: git git://git.infradead.org/~dedekind/ubi-2.6.git
-S: Maintained
-
MICROTEK X6 SCANNER
P: Oliver Neukum
M: oliver@neukum.name
@@ -3038,17 +3028,6 @@ L: netdev@vger.kernel.org
W: http://www.netxen.com
S: Supported
-IPVS
-P: Wensong Zhang
-M: wensong@linux-vs.org
-P: Simon Horman
-M: horms@verge.net.au
-P: Julian Anastasov
-M: ja@ssi.bg
-L: netdev@vger.kernel.org
-L: lvs-devel@vger.kernel.org
-S: Maintained
-
NFS, SUNRPC, AND LOCKD CLIENTS
P: Trond Myklebust
M: Trond.Myklebust@netapp.com
@@ -3094,22 +3073,6 @@ M: adaplas@gmail.com
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
-OPENCORES I2C BUS DRIVER
-P: Peter Korsgaard
-M: jacmet@sunsite.dk
-L: i2c@lm-sensors.org
-S: Maintained
-
-ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
-P: Mark Fasheh
-M: mfasheh@suse.com
-P: Joel Becker
-M: joel.becker@oracle.com
-L: ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
-W: http://oss.oracle.com/projects/ocfs2/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git
-S: Supported
-
OMFS FILESYSTEM
P: Bob Copeland
M: me@bobcopeland.com
@@ -3145,12 +3108,28 @@ L: osst-users@lists.sourceforge.net
L: linux-scsi@vger.kernel.org
S: Maintained
+OPENCORES I2C BUS DRIVER
+P: Peter Korsgaard
+M: jacmet@sunsite.dk
+L: i2c@lm-sensors.org
+S: Maintained
+
OPROFILE
P: Robert Richter
M: robert.richter@amd.com
L: oprofile-list@lists.sf.net
S: Maintained
+ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
+P: Mark Fasheh
+M: mfasheh@suse.com
+P: Joel Becker
+M: joel.becker@oracle.com
+L: ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
+W: http://oss.oracle.com/projects/ocfs2/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git
+S: Supported
+
ORINOCO DRIVER
P: Pavel Roskin
M: proski@gnu.org
@@ -3162,6 +3141,14 @@ L: orinoco-devel@lists.sourceforge.net
W: http://www.nongnu.org/orinoco/
S: Maintained
+P54 WIRELESS DRIVER
+P: Michael Wu
+M: flamingice@sourmilk.net
+L: linux-wireless@vger.kernel.org
+W: http://prism54.org
+T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+S: Maintained
+
PA SEMI ETHERNET DRIVER
P: Olof Johansson
M: olof@lixom.net
@@ -3174,10 +3161,32 @@ M: olof@lixom.net
L: i2c@lm-sensors.org
S: Maintained
+PANASONIC MN10300/AM33 PORT
+P: David Howells
+M: dhowells@redhat.com
+P: Koichi Yasutake
+M: yasutake.koichi@jp.panasonic.com
+L: linux-am33-list@redhat.com (moderated for non-subscribers)
+W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
+S: Maintained
+
PARALLEL PORT SUPPORT
L: linux-parport@lists.infradead.org (subscribers-only)
S: Orphan
+PARAVIRT_OPS INTERFACE
+P: Jeremy Fitzhardinge
+M: jeremy@xensource.com
+P: Chris Wright
+M: chrisw@sous-sol.org
+P: Zachary Amsden
+M: zach@vmware.com
+P: Rusty Russell
+M: rusty@rustcorp.com.au
+L: virtualization@lists.osdl.org
+L: linux-kernel@vger.kernel.org
+S: Supported
+
PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
P: Tim Waugh
M: tim@cyberelk.net
@@ -3197,19 +3206,6 @@ W: http://www.parisc-linux.org/
T: git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
S: Maintained
-PARAVIRT_OPS INTERFACE
-P: Jeremy Fitzhardinge
-M: jeremy@xensource.com
-P: Chris Wright
-M: chrisw@sous-sol.org
-P: Zachary Amsden
-M: zach@vmware.com
-P: Rusty Russell
-M: rusty@rustcorp.com.au
-L: virtualization@lists.osdl.org
-L: linux-kernel@vger.kernel.org
-S: Supported
-
PC87360 HARDWARE MONITORING DRIVER
P: Jim Cromie
M: jim.cromie@gmail.com
@@ -3339,14 +3335,6 @@ L: kpreempt-tech@lists.sourceforge.net
W: ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel
S: Supported
-P54 WIRELESS DRIVER
-P: Michael Wu
-M: flamingice@sourmilk.net
-L: linux-wireless@vger.kernel.org
-W: http://prism54.org
-T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
-S: Maintained
-
PRISM54 WIRELESS DRIVER
P: Luis R. Rodriguez
M: mcgrof@gmail.com
@@ -3437,13 +3425,7 @@ M: paulus@samba.org
L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
-RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
-P: Corey Thomas
-M: coreythomas@charter.net
-L: linux-wireless@vger.kernel.org
-S: Maintained
-
-RALINK RT2X00 WLAN DRIVER
+RALINK RT2X00 WIRELESS LAN DRIVER
P: rt2x00 project
L: linux-wireless@vger.kernel.org
L: rt2400-devel@lists.sourceforge.net
@@ -3468,6 +3450,18 @@ M: mporter@kernel.crashing.org
L: linux-kernel@vger.kernel.org
S: Maintained
+RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
+P: Corey Thomas
+M: coreythomas@charter.net
+L: linux-wireless@vger.kernel.org
+S: Maintained
+
+RCUTORTURE MODULE
+P: Josh Triplett
+M: josh@freedesktop.org
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
RDC R-321X SoC
P: Florian Fainelli
M: florian.fainelli@telecomint.eu
@@ -3487,12 +3481,6 @@ W: http://www.rdrop.com/users/paulmck/rclock/
L: linux-kernel@vger.kernel.org
S: Supported
-RCUTORTURE MODULE
-P: Josh Triplett
-M: josh@freedesktop.org
-L: linux-kernel@vger.kernel.org
-S: Maintained
-
REAL TIME CLOCK DRIVER
P: Paul Gortmaker
M: p_gortmaker@yahoo.com
@@ -3516,6 +3504,9 @@ L: netdev@vger.kernel.org
S: Maintained
F: net/rfkill
+RISCOM8 DRIVER
+S: Orphan
+
ROCKETPORT DRIVER
P: Comtrol Corp.
W: http://www.comtrol.com
@@ -3528,9 +3519,6 @@ L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
-RISCOM8 DRIVER
-S: Orphan
-
RTL818X WIRELESS DRIVER
P: Michael Wu
M: flamingice@sourmilk.net
@@ -3670,6 +3658,12 @@ M: saschasommer@freenet.de
L: sdricohcs-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
+P: Pierre Ossman
+M: drzeus-sdhci@drzeus.cx
+L: sdhci-devel@list.drzeus.cx
+S: Maintained
+
SECURITY CONTACT
P: Security Officers
M: security@kernel.org
@@ -3693,19 +3687,13 @@ P: Jiri Slaby
M: jirislaby@gmail.com
S: Maintained
-SERIAL ATA (SATA) SUBSYSTEM:
+SERIAL ATA (SATA) SUBSYSTEM
P: Jeff Garzik
M: jgarzik@pobox.com
L: linux-ide@vger.kernel.org
T: git kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
S: Supported
-SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
-P: Pat Gefre
-M: pfg@sgi.com
-L: linux-ia64@vger.kernel.org
-S: Supported
-
SFC NETWORK DRIVER
P: Steve Hodgson
P: Ben Hutchings
@@ -3713,6 +3701,17 @@ P: Robert Stonehouse
M: linux-net-drivers@solarflare.com
S: Supported
+SGI GRU DRIVER
+P: Jack Steiner
+M: steiner@sgi.com
+S: Maintained
+
+SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
+P: Pat Gefre
+M: pfg@sgi.com
+L: linux-ia64@vger.kernel.org
+S: Supported
+
SGI VISUAL WORKSTATION 320 AND 540
P: Andrey Panin
M: pazke@donpac.ru
@@ -3720,16 +3719,24 @@ L: linux-visws-devel@lists.sf.net
W: http://linux-visws.sf.net
S: Maintained for 2.6.
-SGI GRU DRIVER
-P: Jack Steiner
-M: steiner@sgi.com
-S: Maintained
-
SGI XP/XPC/XPNET DRIVER
P: Dean Nelson
M: dcn@sgi.com
S: Maintained
+SHARP LH SUPPORT (LH7952X & LH7A40X)
+P: Marc Singer
+M: elf@buici.com
+W: http://projects.buici.com/arm
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S: Maintained
+
+SHPC HOTPLUG DRIVER
+P: Kristen Carlson Accardi
+M: kristen.c.accardi@intel.com
+L: linux-pci@vger.kernel.org
+S: Supported
+
SIMTEC EB110ATX (Chalice CATS)
P: Ben Dooks
P: Vincent Sanders
@@ -3775,6 +3782,12 @@ M: thomas@winischhofer.net
W: http://www.winischhofer.at/linuxsisusbvga.shtml
S: Maintained
+SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
+P: Stephen Hemminger
+M: shemminger@linux-foundation.org
+L: netdev@vger.kernel.org
+S: Maintained
+
SLAB ALLOCATOR
P: Christoph Lameter
M: cl@linux-foundation.org
@@ -3801,12 +3814,25 @@ P: Ben Nizette
M: bn@niasdigital.com
S: Maintained
+SN-IA64 (Itanium) SUB-PLATFORM
+P: Jes Sorensen
+M: jes@sgi.com
+L: linux-altix@sgi.com
+L: linux-ia64@vger.kernel.org
+W: http://www.sgi.com/altix
+S: Maintained
+
SOC-CAMERA V4L2 SUBSYSTEM
P: Guennadi Liakhovetski
M: g.liakhovetski@gmx.de
L: video4linux-list@redhat.com
S: Maintained
+SOEKRIS NET48XX LED SUPPORT
+P: Chris Boot
+M: bootc@bootc.net
+S: Maintained
+
SOFTWARE RAID (Multiple Disks) SUPPORT
P: Ingo Molnar
M: mingo@redhat.com
@@ -3815,24 +3841,6 @@ M: neilb@suse.de
L: linux-raid@vger.kernel.org
S: Supported
-HIBERNATION (aka Software Suspend, aka swsusp):
-P: Pavel Machek
-M: pavel@suse.cz
-P: Rafael J. Wysocki
-M: rjw@sisk.pl
-L: linux-pm@lists.linux-foundation.org
-S: Supported
-
-SUSPEND TO RAM:
-P: Len Brown
-M: len.brown@intel.com
-P: Pavel Machek
-M: pavel@suse.cz
-P: Rafael J. Wysocki
-M: rjw@sisk.pl
-L: linux-pm@lists.linux-foundation.org
-S: Supported
-
SONIC NETWORK DRIVER
P: Thomas Bogendoerfer
M: tsbogend@alpha.franken.de
@@ -3877,59 +3885,7 @@ L: alsa-devel@alsa-project.org (subscribers-only)
W: http://alsa-project.org/main/index.php/ASoC
S: Supported
-SPI SUBSYSTEM
-P: David Brownell
-M: dbrownell@users.sourceforge.net
-L: spi-devel-general@lists.sourceforge.net
-S: Maintained
-
-SPU FILE SYSTEM
-P: Jeremy Kerr
-M: jk@ozlabs.org
-L: linuxppc-dev@ozlabs.org
-L: cbe-oss-dev@ozlabs.org
-W: http://www.ibm.com/developerworks/power/cell/
-S: Supported
-
-STABLE BRANCH:
-P: Greg Kroah-Hartman
-M: greg@kroah.com
-P: Chris Wright
-M: chrisw@sous-sol.org
-L: stable@kernel.org
-S: Maintained
-
-SHARP LH SUPPORT (LH7952X & LH7A40X)
-P: Marc Singer
-M: elf@buici.com
-W: http://projects.buici.com/arm
-L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-S: Maintained
-
-SHPC HOTPLUG DRIVER
-P: Kristen Carlson Accardi
-M: kristen.c.accardi@intel.com
-L: linux-pci@vger.kernel.org
-S: Supported
-
-SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER
-P: Pierre Ossman
-M: drzeus-sdhci@drzeus.cx
-L: sdhci-devel@list.drzeus.cx
-S: Maintained
-
-SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS
-P: Stephen Hemminger
-M: shemminger@linux-foundation.org
-L: netdev@vger.kernel.org
-S: Maintained
-
-SOEKRIS NET48XX LED SUPPORT
-P: Chris Boot
-M: bootc@bootc.net
-S: Maintained
-
-SPARC (sparc32):
+SPARC (sparc32)
P: William L. Irwin
M: wli@holomorphy.com
L: sparclinux@vger.kernel.org
@@ -3941,6 +3897,12 @@ M: R.E.Wolff@BitWizard.nl
L: linux-kernel@vger.kernel.org ?
S: Supported
+SPI SUBSYSTEM
+P: David Brownell
+M: dbrownell@users.sourceforge.net
+L: spi-devel-general@lists.sourceforge.net
+S: Maintained
+
SPIDERNET NETWORK DRIVER for CELL
P: Ishizaki Kou
M: kou.ishizaki@toshiba.co.jp
@@ -3949,12 +3911,28 @@ M: jens@de.ibm.com
L: netdev@vger.kernel.org
S: Supported
+SPU FILE SYSTEM
+P: Jeremy Kerr
+M: jk@ozlabs.org
+L: linuxppc-dev@ozlabs.org
+L: cbe-oss-dev@ozlabs.org
+W: http://www.ibm.com/developerworks/power/cell/
+S: Supported
+
SRM (Alpha) environment access
P: Jan-Benedict Glaw
M: jbglaw@lug-owl.de
L: linux-kernel@vger.kernel.org
S: Maintained
+STABLE BRANCH:
+P: Greg Kroah-Hartman
+M: greg@kroah.com
+P: Chris Wright
+M: chrisw@sous-sol.org
+L: stable@kernel.org
+S: Maintained
+
STARFIRE/DURALAN NETWORK DRIVER
P: Ion Badulescu
M: ionut@cs.columbia.edu
@@ -3970,6 +3948,12 @@ M: laredo@gnu.org
W: http://www.stradis.com/
S: Maintained
+SUN3/3X
+P: Sam Creasey
+M: sammy@sammy.net
+W: http://sammy.net/sun3/
+S: Maintained
+
SUPERH
P: Paul Mundt
M: lethal@linux-sh.org
@@ -3978,11 +3962,15 @@ W: http://www.linux-sh.org
T: git kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6.git
S: Supported
-SUN3/3X
-P: Sam Creasey
-M: sammy@sammy.net
-W: http://sammy.net/sun3/
-S: Maintained
+SUSPEND TO RAM
+P: Len Brown
+M: len.brown@intel.com
+P: Pavel Machek
+M: pavel@suse.cz
+P: Rafael J. Wysocki
+M: rjw@sisk.pl
+L: linux-pm@lists.linux-foundation.org
+S: Supported
SVGA HANDLING
P: Martin Mares
@@ -4028,7 +4016,7 @@ P: Mark Gross
M: mark.gross@intel.com
S: Supported
-TENSILICA XTENSA PORT (xtensa):
+TENSILICA XTENSA PORT (xtensa)
P: Chris Zankel
M: chris@zankel.net
S: Maintained
@@ -4142,6 +4130,16 @@ M: ballabio_dario@emc.com
L: linux-scsi@vger.kernel.org
S: Maintained
+UBI FILE SYSTEM (UBIFS)
+P: Artem Bityutskiy
+M: dedekind@infradead.org
+P: Adrian Hunter
+M: ext-adrian.hunter@nokia.com
+L: linux-mtd@lists.infradead.org
+T: git git://git.infradead.org/~dedekind/ubifs-2.6.git
+W: http://www.linux-mtd.infradead.org/doc/ubifs.html
+S: Maintained
+
UCLINUX (AND M68KNOMMU)
P: Greg Ungerer
M: gerg@uclinux.org
@@ -4167,7 +4165,7 @@ M: dushistov@mail.ru
L: linux-kernel@vger.kernel.org
S: Maintained
-UltraSPARC (sparc64):
+UltraSPARC (sparc64)
P: David S. Miller
M: davem@davemloft.net
L: sparclinux@vger.kernel.org
@@ -4181,6 +4179,14 @@ L: linux-kernel@vger.kernel.org
W: http://www.kernel.dk
S: Maintained
+UNSORTED BLOCK IMAGES (UBI)
+P: Artem Bityutskiy
+M: dedekind@infradead.org
+W: http://www.linux-mtd.infradead.org/
+L: linux-mtd@lists.infradead.org
+T: git git://git.infradead.org/~dedekind/ubi-2.6.git
+S: Maintained
+
USB ACM DRIVER
P: Oliver Neukum
M: oliver@neukum.name
@@ -4450,7 +4456,7 @@ L: video4linux-list@redhat.com
W: http://royale.zerezo.com/zr364xx/
S: Maintained
-USER-MODE LINUX
+USER-MODE LINUX (UML)
P: Jeff Dike
M: jdike@addtoit.com
L: user-mode-linux-devel@lists.sourceforge.net
@@ -4474,7 +4480,7 @@ W: http://kernel.org/~kzak/util-linux-ng/
T: git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git
S: Maintained
-VFAT/FAT/MSDOS FILESYSTEM:
+VFAT/FAT/MSDOS FILESYSTEM
P: OGAWA Hirofumi
M: hirofumi@mail.parknet.co.jp
L: linux-kernel@vger.kernel.org
@@ -4497,7 +4503,7 @@ M: romieu@fr.zoreil.com
L: netdev@vger.kernel.org
S: Maintained
-VIDEO FOR LINUX
+VIDEO FOR LINUX (V4L)
P: Mauro Carvalho Chehab
M: mchehab@infradead.org
M: v4l-dvb-maintainer@linuxtv.org
@@ -4603,6 +4609,17 @@ M: eis@baty.hanse.de
L: linux-x25@vger.kernel.org
S: Maintained
+X86 ARCHITECTURE (32-BIT AND 64-BIT)
+P: Thomas Gleixner
+M: tglx@linutronix.de
+P: Ingo Molnar
+M: mingo@redhat.com
+P: H. Peter Anvin
+M: hpa@zytor.com
+L: linux-kernel@vger.kernel.org
+T: git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
+S: Maintained
+
XEN HYPERVISOR INTERFACE
P: Jeremy Fitzhardinge
M: jeremy@xensource.com
@@ -4634,17 +4651,6 @@ M: jacmet@sunsite.dk
L: linux-serial@vger.kernel.org
S: Maintained
-X86 ARCHITECTURE (32-BIT AND 64-BIT)
-P: Thomas Gleixner
-M: tglx@linutronix.de
-P: Ingo Molnar
-M: mingo@redhat.com
-P: H. Peter Anvin
-M: hpa@zytor.com
-L: linux-kernel@vger.kernel.org
-T: git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
-S: Maintained
-
YAM DRIVER FOR AX.25
P: Jean-Paul Roubelat
M: jpr@f6fbb.org
diff --git a/arch/Kconfig b/arch/Kconfig
index 364c6dadde0..0267babe5eb 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -13,6 +13,20 @@ config OPROFILE
If unsure, say N.
+config OPROFILE_IBS
+ bool "OProfile AMD IBS support (EXPERIMENTAL)"
+ default n
+ depends on OPROFILE && SMP && X86
+ help
+ Instruction-Based Sampling (IBS) is a new profiling
+ technique that provides rich, precise program performance
+ information. IBS is introduced by AMD Family10h processors
+ (AMD Opteron Quad-Core processor “Barcelona”) to overcome
+ the limitations of conventional performance counter
+ sampling.
+
+ If unsure, say N.
+
config HAVE_OPROFILE
def_bool n
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 1bec55d63ef..ee35226c44e 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -5,6 +5,7 @@
config ALPHA
bool
default y
+ select HAVE_AOUT
select HAVE_IDE
select HAVE_OPROFILE
help
@@ -68,9 +69,6 @@ config AUTO_IRQ_AFFINITY
depends on SMP
default y
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
source "init/Kconfig"
diff --git a/arch/alpha/include/asm/statfs.h b/arch/alpha/include/asm/statfs.h
index ad15830baef..de35cd438a1 100644
--- a/arch/alpha/include/asm/statfs.h
+++ b/arch/alpha/include/asm/statfs.h
@@ -1,6 +1,10 @@
#ifndef _ALPHA_STATFS_H
#define _ALPHA_STATFS_H
+/* Alpha is the only 64-bit platform with 32-bit statfs. And doesn't
+ even seem to implement statfs64 */
+#define __statfs_word __u32
+
#include <asm-generic/statfs.h>
#endif
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index efeed65b4a6..4853f9df37b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration"
config ARM
bool
default y
+ select HAVE_AOUT
select HAVE_IDE
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
@@ -140,9 +141,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
config ARCH_MAY_HAVE_PC_FDC
bool
diff --git a/arch/arm/include/asm/statfs.h b/arch/arm/include/asm/statfs.h
index a02e6a8c3d7..079447c05ba 100644
--- a/arch/arm/include/asm/statfs.h
+++ b/arch/arm/include/asm/statfs.h
@@ -1,42 +1,12 @@
#ifndef _ASMARM_STATFS_H
#define _ASMARM_STATFS_H
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t fsid_t;
-#endif
-
-struct statfs {
- __u32 f_type;
- __u32 f_bsize;
- __u32 f_blocks;
- __u32 f_bfree;
- __u32 f_bavail;
- __u32 f_files;
- __u32 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-};
-
/*
* With EABI there is 4 bytes of padding added to this structure.
* Let's pack it so the padding goes away to simplify dual ABI support.
* Note that user space does NOT have to pack this structure.
*/
-struct statfs64 {
- __u32 f_type;
- __u32 f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-} __attribute__ ((packed,aligned(4)));
+#define ARCH_PACK_STATFS64 __attribute__((packed,aligned(4)))
+#include <asm-generic/statfs.h>
#endif
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
index ba99a203552..d006085ed7e 100644
--- a/arch/arm/kernel/dma.c
+++ b/arch/arm/kernel/dma.c
@@ -26,23 +26,6 @@ EXPORT_SYMBOL(dma_spin_lock);
static dma_t dma_chan[MAX_DMA_CHANNELS];
/*
- * Get dma list for /proc/dma
- */
-int get_dma_list(char *buf)
-{
- dma_t *dma;
- char *p = buf;
- int i;
-
- for (i = 0, dma = dma_chan; i < MAX_DMA_CHANNELS; i++, dma++)
- if (dma->lock)
- p += sprintf(p, "%2d: %14s %s\n", i,
- dma->d_ops->type, dma->device_id);
-
- return p - buf;
-}
-
-/*
* Request DMA channel
*
* On certain platforms, we have to allocate an interrupt as well...
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h
index e67c843baa0..9f5ce1ce584 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/include/mach/orion5x.h
@@ -157,9 +157,11 @@
#define CPU_CONF ORION5X_BRIDGE_REG(0x100)
#define CPU_CTRL ORION5X_BRIDGE_REG(0x104)
#define CPU_RESET_MASK ORION5X_BRIDGE_REG(0x108)
+#define WDT_RESET 0x0002
#define CPU_SOFT_RESET ORION5X_BRIDGE_REG(0x10c)
#define POWER_MNG_CTRL_REG ORION5X_BRIDGE_REG(0x11C)
#define BRIDGE_CAUSE ORION5X_BRIDGE_REG(0x110)
+#define WDT_INT_REQ 0x0008
#define BRIDGE_MASK ORION5X_BRIDGE_REG(0x114)
#define BRIDGE_INT_TIMER0 0x0002
#define BRIDGE_INT_TIMER1 0x0004
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index a716ecd1db2..97187fa0ae5 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -441,16 +441,8 @@ static inline void omap_init_uwire(void) {}
#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WDT_BASE 0x48022000
-#else
-#define OMAP_WDT_BASE 0xfffeb000
-#endif
-
static struct resource wdt_resources[] = {
{
- .start = OMAP_WDT_BASE,
- .end = OMAP_WDT_BASE + 0x4f,
.flags = IORESOURCE_MEM,
},
};
@@ -464,6 +456,19 @@ static struct platform_device omap_wdt_device = {
static void omap_init_wdt(void)
{
+ if (cpu_is_omap16xx())
+ wdt_resources[0].start = 0xfffeb000;
+ else if (cpu_is_omap2420())
+ wdt_resources[0].start = 0x48022000; /* WDT2 */
+ else if (cpu_is_omap2430())
+ wdt_resources[0].start = 0x49016000; /* WDT2 */
+ else if (cpu_is_omap343x())
+ wdt_resources[0].start = 0x48314000; /* WDT2 */
+ else
+ return;
+
+ wdt_resources[0].end = wdt_resources[0].start + 0x4f;
+
(void) platform_device_register(&omap_wdt_device);
}
#else
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index b8286f1ce85..6c54580a66d 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -9,6 +9,7 @@
*/
#include <linux/clk.h>
#include <linux/etherdevice.h>
+#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
@@ -53,8 +54,11 @@ static struct spi_board_info spi0_board_info[] __initdata = {
};
static struct mci_platform_data __initdata mci0_data = {
- .detect_pin = GPIO_PIN_PC(25),
- .wp_pin = GPIO_PIN_PE(0),
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = GPIO_PIN_PC(25),
+ .wp_pin = GPIO_PIN_PE(0),
+ },
};
/*
@@ -190,7 +194,7 @@ static int __init atngw100_init(void)
* PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
* but it's not available off-board.
*/
- at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
+ at32_select_periph(GPIO_PIOB_BASE, 1 << 28, 0, AT32_GPIOF_PULLUP);
at32_select_gpio(i2c_gpio_data.sda_pin,
AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
at32_select_gpio(i2c_gpio_data.scl_pin,
@@ -204,6 +208,15 @@ postcore_initcall(atngw100_init);
static int __init atngw100_arch_init(void)
{
+ /* PB30 is the otherwise unused jumper on the mainboard, with an
+ * external pullup; the jumper grounds it. Use it however you
+ * like, including letting U-Boot or Linux tweak boot sequences.
+ */
+ at32_select_gpio(GPIO_PIN_PB(30), 0);
+ gpio_request(GPIO_PIN_PB(30), "j15");
+ gpio_direction_input(GPIO_PIN_PB(30));
+ gpio_export(GPIO_PIN_PB(30), false);
+
/* set_irq_type() after the arch_initcall for EIC has run, and
* before the I2C subsystem could try using this IRQ.
*/
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index dfc3443e23a..29e5b51a7fd 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -232,7 +232,7 @@ static void __init atstk1002_setup_extdac(void)
goto err_set_clk;
}
- at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
at73c213_data.dac_clk = gclk;
err_set_clk:
@@ -264,16 +264,20 @@ void __init setup_board(void)
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
+
/* MMC card detect requires MACB0 *NOT* be used */
#ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
-static struct mci_platform_data __initdata mci0_data = {
- .detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */
- .wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */
-};
-#define MCI_PDATA &mci0_data
+ .detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */
+ .wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */
#else
-#define MCI_PDATA NULL
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
#endif /* SW6 for sd{cd,wp} routing */
+ },
+};
#endif /* SW2 for MMC signal routing */
@@ -326,13 +330,14 @@ static int __init atstk1002_init(void)
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
#endif
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- at32_add_device_mci(0, MCI_PDATA);
+ at32_add_device_mci(0, &mci0_data);
#endif
#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
#else
at32_add_device_lcdc(0, &atstk1000_lcdc_data,
- fbmem_start, fbmem_size, 0);
+ fbmem_start, fbmem_size,
+ ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
#endif
at32_add_device_usba(0, NULL);
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
index 0cf664174c1..be089d7f37e 100644
--- a/arch/avr32/boards/atstk1000/atstk1003.c
+++ b/arch/avr32/boards/atstk1000/atstk1003.c
@@ -19,6 +19,7 @@
#include <linux/spi/spi.h>
#include <asm/setup.h>
+#include <asm/atmel-mci.h>
#include <mach/at32ap700x.h>
#include <mach/board.h>
@@ -66,6 +67,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
} };
#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+};
+#endif
+
#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
static void __init atstk1003_setup_extdac(void)
{
@@ -84,7 +95,7 @@ static void __init atstk1003_setup_extdac(void)
goto err_set_clk;
}
- at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
at73c213_data.dac_clk = gclk;
err_set_clk:
@@ -154,7 +165,7 @@ static int __init atstk1003_init(void)
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
#endif
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- at32_add_device_mci(0, NULL);
+ at32_add_device_mci(0, &mci0_data);
#endif
at32_add_device_usba(0, NULL);
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
index 50a5273e591..248ef237c16 100644
--- a/arch/avr32/boards/atstk1000/atstk1004.c
+++ b/arch/avr32/boards/atstk1000/atstk1004.c
@@ -21,6 +21,7 @@
#include <video/atmel_lcdc.h>
#include <asm/setup.h>
+#include <asm/atmel-mci.h>
#include <mach/at32ap700x.h>
#include <mach/board.h>
@@ -71,6 +72,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
} };
#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+};
+#endif
+
#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
static void __init atstk1004_setup_extdac(void)
{
@@ -89,7 +100,7 @@ static void __init atstk1004_setup_extdac(void)
goto err_set_clk;
}
- at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
at73c213_data.dac_clk = gclk;
err_set_clk:
@@ -137,10 +148,11 @@ static int __init atstk1004_init(void)
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
#endif
#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
- at32_add_device_mci(0, NULL);
+ at32_add_device_mci(0, &mci0_data);
#endif
at32_add_device_lcdc(0, &atstk1000_lcdc_data,
- fbmem_start, fbmem_size, 0);
+ fbmem_start, fbmem_size,
+ ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
at32_add_device_usba(0, NULL);
#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
at32_add_device_ssc(0, ATMEL_SSC_TX);
diff --git a/arch/avr32/include/asm/a.out.h b/arch/avr32/include/asm/a.out.h
deleted file mode 100644
index e46375a34a7..00000000000
--- a/arch/avr32/include/asm/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __ASM_AVR32_A_OUT_H
-#define __ASM_AVR32_A_OUT_H
-
-struct exec
-{
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif /* __ASM_AVR32_A_OUT_H */
diff --git a/arch/avr32/include/asm/atmel-mci.h b/arch/avr32/include/asm/atmel-mci.h
index c2ea6e1c9aa..59f3fadd0b6 100644
--- a/arch/avr32/include/asm/atmel-mci.h
+++ b/arch/avr32/include/asm/atmel-mci.h
@@ -1,9 +1,39 @@
#ifndef __ASM_AVR32_ATMEL_MCI_H
#define __ASM_AVR32_ATMEL_MCI_H
-struct mci_platform_data {
+#define ATMEL_MCI_MAX_NR_SLOTS 2
+
+struct dma_slave;
+
+/**
+ * struct mci_slot_pdata - board-specific per-slot configuration
+ * @bus_width: Number of data lines wired up the slot
+ * @detect_pin: GPIO pin wired to the card detect switch
+ * @wp_pin: GPIO pin wired to the write protect sensor
+ *
+ * If a given slot is not present on the board, @bus_width should be
+ * set to 0. The other fields are ignored in this case.
+ *
+ * Any pins that aren't available should be set to a negative value.
+ *
+ * Note that support for multiple slots is experimental -- some cards
+ * might get upset if we don't get the clock management exactly right.
+ * But in most cases, it should work just fine.
+ */
+struct mci_slot_pdata {
+ unsigned int bus_width;
int detect_pin;
int wp_pin;
};
+/**
+ * struct mci_platform_data - board-specific MMC/SDcard configuration
+ * @dma_slave: DMA slave interface to use in data transfers, or NULL.
+ * @slot: Per-slot configuration data.
+ */
+struct mci_platform_data {
+ struct dma_slave *dma_slave;
+ struct mci_slot_pdata slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
#endif /* __ASM_AVR32_ATMEL_MCI_H */
diff --git a/arch/avr32/include/asm/byteorder.h b/arch/avr32/include/asm/byteorder.h
index d77b48ba733..8e3af02076d 100644
--- a/arch/avr32/include/asm/byteorder.h
+++ b/arch/avr32/include/asm/byteorder.h
@@ -7,6 +7,9 @@
#include <asm/types.h>
#include <linux/compiler.h>
+#define __BIG_ENDIAN
+#define __SWAB_64_THRU_32__
+
#ifdef __CHECKER__
extern unsigned long __builtin_bswap_32(unsigned long x);
extern unsigned short __builtin_bswap_16(unsigned short x);
@@ -17,15 +20,18 @@ extern unsigned short __builtin_bswap_16(unsigned short x);
* the result.
*/
#if !(__GNUC__ == 4 && __GNUC_MINOR__ < 2)
-#define __arch__swab32(x) __builtin_bswap_32(x)
-#define __arch__swab16(x) __builtin_bswap_16(x)
-#endif
+static inline __attribute_const__ __u16 __arch_swab16(__u16 val)
+{
+ return __builtin_bswap_16(val);
+}
+#define __arch_swab16 __arch_swab16
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-# define __BYTEORDER_HAS_U64__
-# define __SWAB_64_THRU_32__
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
+{
+ return __builtin_bswap_32(val);
+}
+#define __arch_swab32 __arch_swab32
#endif
-#include <linux/byteorder/big_endian.h>
-
+#include <linux/byteorder.h>
#endif /* __ASM_AVR32_BYTEORDER_H */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index a520f77ead9..22c97ef9220 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -160,6 +160,14 @@ BUILDIO_IOPORT(l, u32)
#define readw_relaxed readw
#define readl_relaxed readl
+#define readb_be __raw_readb
+#define readw_be __raw_readw
+#define readl_be __raw_readl
+
+#define writeb_be __raw_writeb
+#define writew_be __raw_writew
+#define writel_be __raw_writel
+
#define __BUILD_MEMORY_STRING(bwl, type) \
static inline void writes##bwl(volatile void __iomem *addr, \
const void *data, unsigned int count) \
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 2c08ac992ac..134d5302b6d 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/fs.h>
+#include <linux/pm.h>
#include <linux/ptrace.h>
#include <linux/reboot.h>
#include <linux/tick.h>
@@ -20,7 +21,7 @@
#include <mach/pm.h>
-void (*pm_power_off)(void) = NULL;
+void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
/*
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index d8e623c426c..5c7083916c3 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -283,6 +283,25 @@ static int __init early_parse_fbmem(char *p)
}
early_param("fbmem", early_parse_fbmem);
+/*
+ * Pick out the memory size. We look for mem=size@start,
+ * where start and size are "size[KkMmGg]"
+ */
+static int __init early_mem(char *p)
+{
+ resource_size_t size, start;
+
+ start = system_ram->start;
+ size = memparse(p, &p);
+ if (*p == '@')
+ start = memparse(p + 1, &p);
+
+ system_ram->start = start;
+ system_ram->end = system_ram->start + size - 1;
+ return 0;
+}
+early_param("mem", early_mem);
+
static int __init parse_tag_core(struct tag *tag)
{
if (tag->hdr.size > 2) {
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index e01dbe4ebb4..813b6844cdf 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -82,8 +82,9 @@ static struct platform_device _name##_id##_device = { \
.num_resources = ARRAY_SIZE(_name##_id##_resource), \
}
-#define select_peripheral(pin, periph, flags) \
- at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+#define select_peripheral(port, pin_mask, periph, flags) \
+ at32_select_periph(GPIO_##port##_BASE, pin_mask, \
+ GPIO_##periph, flags)
#define DEV_CLK(_name, devname, bus, _index) \
static struct clk devname##_##_name = { \
@@ -871,6 +872,7 @@ static struct clk atmel_psif1_pclk = {
struct platform_device *__init at32_add_device_psif(unsigned int id)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (!(id == 0 || id == 1))
return NULL;
@@ -881,20 +883,22 @@ struct platform_device *__init at32_add_device_psif(unsigned int id)
switch (id) {
case 0:
+ pin_mask = (1 << 8) | (1 << 9); /* CLOCK & DATA */
+
if (platform_device_add_resources(pdev, atmel_psif0_resource,
ARRAY_SIZE(atmel_psif0_resource)))
goto err_add_resources;
atmel_psif0_pclk.dev = &pdev->dev;
- select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
- select_peripheral(PA(9), PERIPH_A, 0); /* DATA */
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
break;
case 1:
+ pin_mask = (1 << 11) | (1 << 12); /* CLOCK & DATA */
+
if (platform_device_add_resources(pdev, atmel_psif1_resource,
ARRAY_SIZE(atmel_psif1_resource)))
goto err_add_resources;
atmel_psif1_pclk.dev = &pdev->dev;
- select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
- select_peripheral(PB(12), PERIPH_A, 0); /* DATA */
+ select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
break;
default:
return NULL;
@@ -958,26 +962,30 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
static inline void configure_usart0_pins(void)
{
- select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
- select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
+ u32 pin_mask = (1 << 8) | (1 << 9); /* RXD & TXD */
+
+ select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
}
static inline void configure_usart1_pins(void)
{
- select_peripheral(PA(17), PERIPH_A, 0); /* RXD */
- select_peripheral(PA(18), PERIPH_A, 0); /* TXD */
+ u32 pin_mask = (1 << 17) | (1 << 18); /* RXD & TXD */
+
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
}
static inline void configure_usart2_pins(void)
{
- select_peripheral(PB(26), PERIPH_B, 0); /* RXD */
- select_peripheral(PB(27), PERIPH_B, 0); /* TXD */
+ u32 pin_mask = (1 << 26) | (1 << 27); /* RXD & TXD */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
}
static inline void configure_usart3_pins(void)
{
- select_peripheral(PB(18), PERIPH_B, 0); /* RXD */
- select_peripheral(PB(17), PERIPH_B, 0); /* TXD */
+ u32 pin_mask = (1 << 18) | (1 << 17); /* RXD & TXD */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
}
static struct platform_device *__initdata at32_usarts[4];
@@ -1057,59 +1065,69 @@ struct platform_device *__init
at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
{
struct platform_device *pdev;
+ u32 pin_mask;
switch (id) {
case 0:
pdev = &macb0_device;
- select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */
- select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */
- select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */
- select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */
- select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */
- select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
- select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
- select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
- select_peripheral(PC(16), PERIPH_A, 0); /* MDC */
- select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
+ pin_mask = (1 << 3); /* TXD0 */
+ pin_mask |= (1 << 4); /* TXD1 */
+ pin_mask |= (1 << 7); /* TXEN */
+ pin_mask |= (1 << 8); /* TXCK */
+ pin_mask |= (1 << 9); /* RXD0 */
+ pin_mask |= (1 << 10); /* RXD1 */
+ pin_mask |= (1 << 13); /* RXER */
+ pin_mask |= (1 << 15); /* RXDV */
+ pin_mask |= (1 << 16); /* MDC */
+ pin_mask |= (1 << 17); /* MDIO */
if (!data->is_rmii) {
- select_peripheral(PC(0), PERIPH_A, 0); /* COL */
- select_peripheral(PC(1), PERIPH_A, 0); /* CRS */
- select_peripheral(PC(2), PERIPH_A, 0); /* TXER */
- select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */
- select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */
- select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
- select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
- select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
- select_peripheral(PC(18), PERIPH_A, 0); /* SPD */
+ pin_mask |= (1 << 0); /* COL */
+ pin_mask |= (1 << 1); /* CRS */
+ pin_mask |= (1 << 2); /* TXER */
+ pin_mask |= (1 << 5); /* TXD2 */
+ pin_mask |= (1 << 6); /* TXD3 */
+ pin_mask |= (1 << 11); /* RXD2 */
+ pin_mask |= (1 << 12); /* RXD3 */
+ pin_mask |= (1 << 14); /* RXCK */
+ pin_mask |= (1 << 18); /* SPD */
}
+
+ select_peripheral(PIOC, pin_mask, PERIPH_A, 0);
+
break;
case 1:
pdev = &macb1_device;
- select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */
- select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */
- select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */
- select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */
- select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */
- select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */
- select_peripheral(PD(5), PERIPH_B, 0); /* RXER */
- select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */
- select_peripheral(PD(3), PERIPH_B, 0); /* MDC */
- select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */
+ pin_mask = (1 << 13); /* TXD0 */
+ pin_mask |= (1 << 14); /* TXD1 */
+ pin_mask |= (1 << 11); /* TXEN */
+ pin_mask |= (1 << 12); /* TXCK */
+ pin_mask |= (1 << 10); /* RXD0 */
+ pin_mask |= (1 << 6); /* RXD1 */
+ pin_mask |= (1 << 5); /* RXER */
+ pin_mask |= (1 << 4); /* RXDV */
+ pin_mask |= (1 << 3); /* MDC */
+ pin_mask |= (1 << 2); /* MDIO */
+
+ if (!data->is_rmii)
+ pin_mask |= (1 << 15); /* SPD */
+
+ select_peripheral(PIOD, pin_mask, PERIPH_B, 0);
if (!data->is_rmii) {
- select_peripheral(PC(19), PERIPH_B, 0); /* COL */
- select_peripheral(PC(23), PERIPH_B, 0); /* CRS */
- select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
- select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
- select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
- select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
- select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
- select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
- select_peripheral(PD(15), PERIPH_B, 0); /* SPD */
+ pin_mask = (1 << 19); /* COL */
+ pin_mask |= (1 << 23); /* CRS */
+ pin_mask |= (1 << 26); /* TXER */
+ pin_mask |= (1 << 27); /* TXD2 */
+ pin_mask |= (1 << 28); /* TXD3 */
+ pin_mask |= (1 << 29); /* RXD2 */
+ pin_mask |= (1 << 30); /* RXD3 */
+ pin_mask |= (1 << 24); /* RXCK */
+
+ select_peripheral(PIOC, pin_mask, PERIPH_B, 0);
}
break;
@@ -1177,23 +1195,28 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
struct platform_device *pdev;
+ u32 pin_mask;
switch (id) {
case 0:
pdev = &atmel_spi0_device;
+ pin_mask = (1 << 1) | (1 << 2); /* MOSI & SCK */
+
/* pullup MISO so a level is always defined */
- select_peripheral(PA(0), PERIPH_A, AT32_GPIOF_PULLUP);
- select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
- select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
+ select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP);
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
at32_spi_setup_slaves(0, b, n, spi0_pins);
break;
case 1:
pdev = &atmel_spi1_device;
+ pin_mask = (1 << 1) | (1 << 5); /* MOSI */
+
/* pullup MISO so a level is always defined */
- select_peripheral(PB(0), PERIPH_B, AT32_GPIOF_PULLUP);
- select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
- select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
+ select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP);
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
+
at32_spi_setup_slaves(1, b, n, spi1_pins);
break;
@@ -1226,6 +1249,7 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
unsigned int n)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (id != 0)
return NULL;
@@ -1238,8 +1262,9 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
ARRAY_SIZE(atmel_twi0_resource)))
goto err_add_resources;
- select_peripheral(PA(6), PERIPH_A, 0); /* SDA */
- select_peripheral(PA(7), PERIPH_A, 0); /* SDL */
+ pin_mask = (1 << 6) | (1 << 7); /* SDA & SDL */
+
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
atmel_twi0_pclk.dev = &pdev->dev;
@@ -1272,10 +1297,16 @@ static struct clk atmel_mci0_pclk = {
struct platform_device *__init
at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
{
- struct mci_platform_data _data;
struct platform_device *pdev;
+ struct dw_dma_slave *dws;
+ u32 pioa_mask;
+ u32 piob_mask;
- if (id != 0)
+ if (id != 0 || !data)
+ return NULL;
+
+ /* Must have at least one usable slot */
+ if (!data->slot[0].bus_width && !data->slot[1].bus_width)
return NULL;
pdev = platform_device_alloc("atmel_mci", id);
@@ -1286,28 +1317,80 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
ARRAY_SIZE(atmel_mci0_resource)))
goto fail;
- if (!data) {
- data = &_data;
- memset(data, -1, sizeof(struct mci_platform_data));
- data->detect_pin = GPIO_PIN_NONE;
- data->wp_pin = GPIO_PIN_NONE;
- }
+ if (data->dma_slave)
+ dws = kmemdup(to_dw_dma_slave(data->dma_slave),
+ sizeof(struct dw_dma_slave), GFP_KERNEL);
+ else
+ dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
+
+ dws->slave.dev = &pdev->dev;
+ dws->slave.dma_dev = &dw_dmac0_device.dev;
+ dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
+ dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
+ | DWC_CFGH_DST_PER(1));
+ dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
+ | DWC_CFGL_HS_SRC_POL);
+
+ data->dma_slave = &dws->slave;
if (platform_device_add_data(pdev, data,
sizeof(struct mci_platform_data)))
goto fail;
- select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
- select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
- select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
- select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
+ /* CLK line is common to both slots */
+ pioa_mask = 1 << 10;
- if (gpio_is_valid(data->detect_pin))
- at32_select_gpio(data->detect_pin, 0);
- if (gpio_is_valid(data->wp_pin))
- at32_select_gpio(data->wp_pin, 0);
+ switch (data->slot[0].bus_width) {
+ case 4:
+ pioa_mask |= 1 << 13; /* DATA1 */
+ pioa_mask |= 1 << 14; /* DATA2 */
+ pioa_mask |= 1 << 15; /* DATA3 */
+ /* fall through */
+ case 1:
+ pioa_mask |= 1 << 11; /* CMD */
+ pioa_mask |= 1 << 12; /* DATA0 */
+
+ if (gpio_is_valid(data->slot[0].detect_pin))
+ at32_select_gpio(data->slot[0].detect_pin, 0);
+ if (gpio_is_valid(data->slot[0].wp_pin))
+ at32_select_gpio(data->slot[0].wp_pin, 0);
+ break;
+ case 0:
+ /* Slot is unused */
+ break;
+ default:
+ goto fail;
+ }
+
+ select_peripheral(PIOA, pioa_mask, PERIPH_A, 0);
+ piob_mask = 0;
+
+ switch (data->slot[1].bus_width) {
+ case 4:
+ piob_mask |= 1 << 8; /* DATA1 */
+ piob_mask |= 1 << 9; /* DATA2 */
+ piob_mask |= 1 << 10; /* DATA3 */
+ /* fall through */
+ case 1:
+ piob_mask |= 1 << 6; /* CMD */
+ piob_mask |= 1 << 7; /* DATA0 */
+ select_peripheral(PIOB, piob_mask, PERIPH_B, 0);
+
+ if (gpio_is_valid(data->slot[1].detect_pin))
+ at32_select_gpio(data->slot[1].detect_pin, 0);
+ if (gpio_is_valid(data->slot[1].wp_pin))
+ at32_select_gpio(data->slot[1].wp_pin, 0);
+ break;
+ case 0:
+ /* Slot is unused */
+ break;
+ default:
+ if (!data->slot[0].bus_width)
+ goto fail;
+
+ data->slot[1].bus_width = 0;
+ break;
+ }
atmel_mci0_pclk.dev = &pdev->dev;
@@ -1353,13 +1436,14 @@ static struct clk atmel_lcdfb0_pixclk = {
struct platform_device *__init
at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
unsigned long fbmem_start, unsigned long fbmem_len,
- unsigned int pin_config)
+ u64 pin_mask)
{
struct platform_device *pdev;
struct atmel_lcdfb_info *info;
struct fb_monspecs *monspecs;
struct fb_videomode *modedb;
unsigned int modedb_size;
+ u32 portc_mask, portd_mask, porte_mask;
/*
* Do a deep copy of the fb data, monspecs and modedb. Make
@@ -1381,76 +1465,21 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
case 0:
pdev = &atmel_lcdfb0_device;
- switch (pin_config) {
- case 0:
- select_peripheral(PC(19), PERIPH_A, 0); /* CC */
- select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
- select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
- select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
- select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
- select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
- select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
- select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
- select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
- select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
- select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
- select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
- select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
- select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
- select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
- select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
- select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
- select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
- select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
- select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
- select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
- select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
- select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
- select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
- select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
- select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
- select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
- select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
- select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
- break;
- case 1:
- select_peripheral(PE(0), PERIPH_B, 0); /* CC */
- select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
- select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
- select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
- select_peripheral(PE(1), PERIPH_B, 0); /* DVAL */
- select_peripheral(PE(2), PERIPH_B, 0); /* MODE */
- select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
- select_peripheral(PE(3), PERIPH_B, 0); /* DATA0 */
- select_peripheral(PE(4), PERIPH_B, 0); /* DATA1 */
- select_peripheral(PE(5), PERIPH_B, 0); /* DATA2 */
- select_peripheral(PE(6), PERIPH_B, 0); /* DATA3 */
- select_peripheral(PE(7), PERIPH_B, 0); /* DATA4 */
- select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
- select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
- select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
- select_peripheral(PE(8), PERIPH_B, 0); /* DATA8 */
- select_peripheral(PE(9), PERIPH_B, 0); /* DATA9 */
- select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
- select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
- select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
- select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
- select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
- select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
- select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
- select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
- select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
- select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
- select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
- select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
- select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
- select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
- break;
- default:
- goto err_invalid_id;
- }
+ if (pin_mask == 0ULL)
+ /* Default to "full" lcdc control signals and 24bit */
+ pin_mask = ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL;
+
+ /* LCDC on port C */
+ portc_mask = (pin_mask & 0xfff80000) >> 19;
+ select_peripheral(PIOC, portc_mask, PERIPH_A, 0);
+
+ /* LCDC on port D */
+ portd_mask = pin_mask & 0x0003ffff;
+ select_peripheral(PIOD, portd_mask, PERIPH_A, 0);
+
+ /* LCDC on port E */
+ porte_mask = (pin_mask >> 32) & 0x0007ffff;
+ select_peripheral(PIOE, porte_mask, PERIPH_B, 0);
clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1499,6 +1528,7 @@ static struct clk atmel_pwm0_mck = {
struct platform_device *__init at32_add_device_pwm(u32 mask)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (!mask)
return NULL;
@@ -1514,14 +1544,21 @@ struct platform_device *__init at32_add_device_pwm(u32 mask)
if (platform_device_add_data(pdev, &mask, sizeof(mask)))
goto out_free_pdev;
+ pin_mask = 0;
if (mask & (1 << 0))
- select_peripheral(PA(28), PERIPH_A, 0);
+ pin_mask |= (1 << 28);
if (mask & (1 << 1))
- select_peripheral(PA(29), PERIPH_A, 0);
+ pin_mask |= (1 << 29);
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
+ pin_mask = 0;
if (mask & (1 << 2))
- select_peripheral(PA(21), PERIPH_B, 0);
+ pin_mask |= (1 << 21);
if (mask & (1 << 3))
- select_peripheral(PA(22), PERIPH_B, 0);
+ pin_mask |= (1 << 22);
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
atmel_pwm0_mck.dev = &pdev->dev;
@@ -1562,52 +1599,65 @@ struct platform_device *__init
at32_add_device_ssc(unsigned int id, unsigned int flags)
{
struct platform_device *pdev;
+ u32 pin_mask = 0;
switch (id) {
case 0:
pdev = &ssc0_device;
if (flags & ATMEL_SSC_RF)
- select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+ pin_mask |= (1 << 21); /* RF */
if (flags & ATMEL_SSC_RK)
- select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+ pin_mask |= (1 << 22); /* RK */
if (flags & ATMEL_SSC_TK)
- select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+ pin_mask |= (1 << 23); /* TK */
if (flags & ATMEL_SSC_TF)
- select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+ pin_mask |= (1 << 24); /* TF */
if (flags & ATMEL_SSC_TD)
- select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+ pin_mask |= (1 << 25); /* TD */
if (flags & ATMEL_SSC_RD)
- select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+ pin_mask |= (1 << 26); /* RD */
+
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
break;
case 1:
pdev = &ssc1_device;
if (flags & ATMEL_SSC_RF)
- select_peripheral(PA(0), PERIPH_B, 0); /* RF */
+ pin_mask |= (1 << 0); /* RF */
if (flags & ATMEL_SSC_RK)
- select_peripheral(PA(1), PERIPH_B, 0); /* RK */
+ pin_mask |= (1 << 1); /* RK */
if (flags & ATMEL_SSC_TK)
- select_peripheral(PA(2), PERIPH_B, 0); /* TK */
+ pin_mask |= (1 << 2); /* TK */
if (flags & ATMEL_SSC_TF)
- select_peripheral(PA(3), PERIPH_B, 0); /* TF */
+ pin_mask |= (1 << 3); /* TF */
if (flags & ATMEL_SSC_TD)
- select_peripheral(PA(4), PERIPH_B, 0); /* TD */
+ pin_mask |= (1 << 4); /* TD */
if (flags & ATMEL_SSC_RD)
- select_peripheral(PA(5), PERIPH_B, 0); /* RD */
+ pin_mask |= (1 << 5); /* RD */
+
+ if (pin_mask > 0)
+ select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
+
break;
case 2:
pdev = &ssc2_device;
if (flags & ATMEL_SSC_TD)
- select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+ pin_mask |= (1 << 13); /* TD */
if (flags & ATMEL_SSC_RD)
- select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+ pin_mask |= (1 << 14); /* RD */
if (flags & ATMEL_SSC_TK)
- select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+ pin_mask |= (1 << 15); /* TK */
if (flags & ATMEL_SSC_TF)
- select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+ pin_mask |= (1 << 16); /* TF */
if (flags & ATMEL_SSC_RF)
- select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+ pin_mask |= (1 << 17); /* RF */
if (flags & ATMEL_SSC_RK)
- select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+ pin_mask |= (1 << 18); /* RK */
+
+ if (pin_mask > 0)
+ select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
+
break;
default:
return NULL;
@@ -1745,14 +1795,15 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
unsigned int cs, unsigned int extint)
{
static unsigned int extint_pin_map[4] __initdata = {
- GPIO_PIN_PB(25),
- GPIO_PIN_PB(26),
- GPIO_PIN_PB(27),
- GPIO_PIN_PB(28),
+ (1 << 25),
+ (1 << 26),
+ (1 << 27),
+ (1 << 28),
};
static bool common_pins_initialized __initdata = false;
unsigned int extint_pin;
int ret;
+ u32 pin_mask;
if (extint >= ARRAY_SIZE(extint_pin_map))
return -EINVAL;
@@ -1766,7 +1817,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
if (ret)
return ret;
- select_peripheral(PE(21), PERIPH_A, 0); /* NCS4 -> OE_N */
+ /* NCS4 -> OE_N */
+ select_peripheral(PIOE, (1 << 21), PERIPH_A, 0);
hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF0_ENABLE);
break;
case 5:
@@ -1776,7 +1828,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
if (ret)
return ret;
- select_peripheral(PE(22), PERIPH_A, 0); /* NCS5 -> OE_N */
+ /* NCS5 -> OE_N */
+ select_peripheral(PIOE, (1 << 22), PERIPH_A, 0);
hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF1_ENABLE);
break;
default:
@@ -1784,14 +1837,17 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
}
if (!common_pins_initialized) {
- select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1 -> CS0_N */
- select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2 -> CS1_N */
- select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW -> DIR */
- select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT <- IORDY */
+ pin_mask = (1 << 19); /* CFCE1 -> CS0_N */
+ pin_mask |= (1 << 20); /* CFCE2 -> CS1_N */
+ pin_mask |= (1 << 23); /* CFRNW -> DIR */
+ pin_mask |= (1 << 24); /* NWAIT <- IORDY */
+
+ select_peripheral(PIOE, pin_mask, PERIPH_A, 0);
+
common_pins_initialized = true;
}
- at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+ select_peripheral(PIOB, extint_pin, PERIPH_A, AT32_GPIOF_DEGLITCH);
pdev->resource[1].start = EIM_IRQ_BASE + extint;
pdev->resource[1].end = pdev->resource[1].start;
@@ -1930,6 +1986,7 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
{
struct platform_device *pdev;
struct ac97c_platform_data _data;
+ u32 pin_mask;
if (id != 0)
return NULL;
@@ -1956,10 +2013,10 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
sizeof(struct ac97c_platform_data)))
goto fail;
- select_peripheral(PB(20), PERIPH_B, 0); /* SDO */
- select_peripheral(PB(21), PERIPH_B, 0); /* SYNC */
- select_peripheral(PB(22), PERIPH_B, 0); /* SCLK */
- select_peripheral(PB(23), PERIPH_B, 0); /* SDI */
+ pin_mask = (1 << 20) | (1 << 21); /* SDO & SYNC */
+ pin_mask |= (1 << 22) | (1 << 23); /* SCLK & SDI */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
/* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
if (data->reset_pin != GPIO_PIN_NONE)
@@ -2001,6 +2058,7 @@ static struct clk abdac0_sample_clk = {
struct platform_device *__init at32_add_device_abdac(unsigned int id)
{
struct platform_device *pdev;
+ u32 pin_mask;
if (id != 0)
return NULL;
@@ -2013,10 +2071,10 @@ struct platform_device *__init at32_add_device_abdac(unsigned int id)
ARRAY_SIZE(abdac0_resource)))
goto err_add_resources;
- select_peripheral(PB(20), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PB(21), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1 */
- select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0 */
+ pin_mask = (1 << 20) | (1 << 22); /* DATA1 & DATAN1 */
+ pin_mask |= (1 << 21) | (1 << 23); /* DATA0 & DATAN0 */
+
+ select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
abdac0_pclk.dev = &pdev->dev;
abdac0_sample_clk.dev = &pdev->dev;
@@ -2073,7 +2131,7 @@ static struct clk gclk4 = {
.index = 4,
};
-struct clk *at32_clock_list[] = {
+static __initdata struct clk *init_clocks[] = {
&osc32k,
&osc0,
&osc1,
@@ -2137,7 +2195,6 @@ struct clk *at32_clock_list[] = {
&gclk3,
&gclk4,
};
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
void __init setup_platform(void)
{
@@ -2168,14 +2225,19 @@ void __init setup_platform(void)
genclk_init_parent(&abdac0_sample_clk);
/*
- * Turn on all clocks that have at least one user already, and
- * turn off everything else. We only do this for module
- * clocks, and even though it isn't particularly pretty to
- * check the address of the mode function, it should do the
- * trick...
+ * Build initial dynamic clock list by registering all clocks
+ * from the array.
+ * At the same time, turn on all clocks that have at least one
+ * user already, and turn off everything else. We only do this
+ * for module clocks, and even though it isn't particularly
+ * pretty to check the address of the mode function, it should
+ * do the trick...
*/
- for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
- struct clk *clk = at32_clock_list[i];
+ for (i = 0; i < ARRAY_SIZE(init_clocks); i++) {
+ struct clk *clk = init_clocks[i];
+
+ /* first, register clock */
+ at32_clk_register(clk);
if (clk->users == 0)
continue;
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
index 6c27ddac5ad..138a00a2a2d 100644
--- a/arch/avr32/mach-at32ap/clock.c
+++ b/arch/avr32/mach-at32ap/clock.c
@@ -15,24 +15,40 @@
#include <linux/err.h>
#include <linux/device.h>
#include <linux/string.h>
+#include <linux/list.h>
#include <mach/chip.h>
#include "clock.h"
+/* at32 clock list */
+static LIST_HEAD(at32_clock_list);
+
static DEFINE_SPINLOCK(clk_lock);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+void at32_clk_register(struct clk *clk)
+{
+ spin_lock(&clk_list_lock);
+ /* add the new item to the end of the list */
+ list_add_tail(&clk->list, &at32_clock_list);
+ spin_unlock(&clk_list_lock);
+}
struct clk *clk_get(struct device *dev, const char *id)
{
- int i;
+ struct clk *clk;
- for (i = 0; i < at32_nr_clocks; i++) {
- struct clk *clk = at32_clock_list[i];
+ spin_lock(&clk_list_lock);
- if (clk->dev == dev && strcmp(id, clk->name) == 0)
+ list_for_each_entry(clk, &at32_clock_list, list) {
+ if (clk->dev == dev && strcmp(id, clk->name) == 0) {
+ spin_unlock(&clk_list_lock);
return clk;
+ }
}
+ spin_unlock(&clk_list_lock);
return ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get);
@@ -203,8 +219,8 @@ dump_clock(struct clk *parent, struct clkinf *r)
/* cost of this scan is small, but not linear... */
r->nest = nest + NEST_DELTA;
- for (i = 3; i < at32_nr_clocks; i++) {
- clk = at32_clock_list[i];
+
+ list_for_each_entry(clk, &at32_clock_list, list) {
if (clk->parent == parent)
dump_clock(clk, r);
}
@@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused)
{
struct clkinf r;
int i;
+ struct clk *clk;
/* show all the power manager registers */
seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL));
@@ -234,14 +251,25 @@ static int clk_show(struct seq_file *s, void *unused)
seq_printf(s, "\n");
- /* show clock tree as derived from the three oscillators
- * we "know" are at the head of the list
- */
r.s = s;
r.nest = 0;
- dump_clock(at32_clock_list[0], &r);
- dump_clock(at32_clock_list[1], &r);
- dump_clock(at32_clock_list[2], &r);
+ /* protected from changes on the list while dumping */
+ spin_lock(&clk_list_lock);
+
+ /* show clock tree as derived from the three oscillators */
+ clk = clk_get(NULL, "osc32k");
+ dump_clock(clk, &r);
+ clk_put(clk);
+
+ clk = clk_get(NULL, "osc0");
+ dump_clock(clk, &r);
+ clk_put(clk);
+
+ clk = clk_get(NULL, "osc1");
+ dump_clock(clk, &r);
+ clk_put(clk);
+
+ spin_unlock(&clk_list_lock);
return 0;
}
diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h
index bb8e1f29583..623bf0e9a1e 100644
--- a/arch/avr32/mach-at32ap/clock.h
+++ b/arch/avr32/mach-at32ap/clock.h
@@ -12,8 +12,13 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
+#include <linux/list.h>
+
+
+void at32_clk_register(struct clk *clk);
struct clk {
+ struct list_head list; /* linking element */
const char *name; /* Clock name/function */
struct device *dev; /* Device the clock is used by */
struct clk *parent; /* Parent clock, if any */
@@ -25,6 +30,3 @@ struct clk {
u16 users; /* Enabled if non-zero */
u16 index; /* Sibling index */
};
-
-extern struct clk *at32_clock_list[];
-extern unsigned int at32_nr_clocks;
diff --git a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
index 1e9852d65cc..a77d372f6f3 100644
--- a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
+++ b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
@@ -83,4 +83,132 @@
#define HMATRIX_BASE 0xfff00800
#define SDRAMC_BASE 0xfff03800
+/* LCDC on port C */
+#define ATMEL_LCDC_PC_CC (1ULL << 19)
+#define ATMEL_LCDC_PC_HSYNC (1ULL << 20)
+#define ATMEL_LCDC_PC_PCLK (1ULL << 21)
+#define ATMEL_LCDC_PC_VSYNC (1ULL << 22)
+#define ATMEL_LCDC_PC_DVAL (1ULL << 23)
+#define ATMEL_LCDC_PC_MODE (1ULL << 24)
+#define ATMEL_LCDC_PC_PWR (1ULL << 25)
+#define ATMEL_LCDC_PC_DATA0 (1ULL << 26)
+#define ATMEL_LCDC_PC_DATA1 (1ULL << 27)
+#define ATMEL_LCDC_PC_DATA2 (1ULL << 28)
+#define ATMEL_LCDC_PC_DATA3 (1ULL << 29)
+#define ATMEL_LCDC_PC_DATA4 (1ULL << 30)
+#define ATMEL_LCDC_PC_DATA5 (1ULL << 31)
+
+/* LCDC on port D */
+#define ATMEL_LCDC_PD_DATA6 (1ULL << 0)
+#define ATMEL_LCDC_PD_DATA7 (1ULL << 1)
+#define ATMEL_LCDC_PD_DATA8 (1ULL << 2)
+#define ATMEL_LCDC_PD_DATA9 (1ULL << 3)
+#define ATMEL_LCDC_PD_DATA10 (1ULL << 4)
+#define ATMEL_LCDC_PD_DATA11 (1ULL << 5)
+#define ATMEL_LCDC_PD_DATA12 (1ULL << 6)
+#define ATMEL_LCDC_PD_DATA13 (1ULL << 7)
+#define ATMEL_LCDC_PD_DATA14 (1ULL << 8)
+#define ATMEL_LCDC_PD_DATA15 (1ULL << 9)
+#define ATMEL_LCDC_PD_DATA16 (1ULL << 10)
+#define ATMEL_LCDC_PD_DATA17 (1ULL << 11)
+#define ATMEL_LCDC_PD_DATA18 (1ULL << 12)
+#define ATMEL_LCDC_PD_DATA19 (1ULL << 13)
+#define ATMEL_LCDC_PD_DATA20 (1ULL << 14)
+#define ATMEL_LCDC_PD_DATA21 (1ULL << 15)
+#define ATMEL_LCDC_PD_DATA22 (1ULL << 16)
+#define ATMEL_LCDC_PD_DATA23 (1ULL << 17)
+
+/* LCDC on port E */
+#define ATMEL_LCDC_PE_CC (1ULL << (32 + 0))
+#define ATMEL_LCDC_PE_DVAL (1ULL << (32 + 1))
+#define ATMEL_LCDC_PE_MODE (1ULL << (32 + 2))
+#define ATMEL_LCDC_PE_DATA0 (1ULL << (32 + 3))
+#define ATMEL_LCDC_PE_DATA1 (1ULL << (32 + 4))
+#define ATMEL_LCDC_PE_DATA2 (1ULL << (32 + 5))
+#define ATMEL_LCDC_PE_DATA3 (1ULL << (32 + 6))
+#define ATMEL_LCDC_PE_DATA4 (1ULL << (32 + 7))
+#define ATMEL_LCDC_PE_DATA8 (1ULL << (32 + 8))
+#define ATMEL_LCDC_PE_DATA9 (1ULL << (32 + 9))
+#define ATMEL_LCDC_PE_DATA10 (1ULL << (32 + 10))
+#define ATMEL_LCDC_PE_DATA11 (1ULL << (32 + 11))
+#define ATMEL_LCDC_PE_DATA12 (1ULL << (32 + 12))
+#define ATMEL_LCDC_PE_DATA16 (1ULL << (32 + 13))
+#define ATMEL_LCDC_PE_DATA17 (1ULL << (32 + 14))
+#define ATMEL_LCDC_PE_DATA18 (1ULL << (32 + 15))
+#define ATMEL_LCDC_PE_DATA19 (1ULL << (32 + 16))
+#define ATMEL_LCDC_PE_DATA20 (1ULL << (32 + 17))
+#define ATMEL_LCDC_PE_DATA21 (1ULL << (32 + 18))
+
+
+#define ATMEL_LCDC(PORT, PIN) (ATMEL_LCDC_##PORT##_##PIN)
+
+
+#define ATMEL_LCDC_PRI_24B_DATA ( \
+ ATMEL_LCDC(PC, DATA0) | ATMEL_LCDC(PC, DATA1) | \
+ ATMEL_LCDC(PC, DATA2) | ATMEL_LCDC(PC, DATA3) | \
+ ATMEL_LCDC(PC, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PD, DATA6) | ATMEL_LCDC(PD, DATA7) | \
+ ATMEL_LCDC(PD, DATA8) | ATMEL_LCDC(PD, DATA9) | \
+ ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) | \
+ ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA13) | \
+ ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) | \
+ ATMEL_LCDC(PD, DATA16) | ATMEL_LCDC(PD, DATA17) | \
+ ATMEL_LCDC(PD, DATA18) | ATMEL_LCDC(PD, DATA19) | \
+ ATMEL_LCDC(PD, DATA20) | ATMEL_LCDC(PD, DATA21) | \
+ ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_ALT_24B_DATA ( \
+ ATMEL_LCDC(PE, DATA0) | ATMEL_LCDC(PE, DATA1) | \
+ ATMEL_LCDC(PE, DATA2) | ATMEL_LCDC(PE, DATA3) | \
+ ATMEL_LCDC(PE, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PD, DATA6) | ATMEL_LCDC(PD, DATA7) | \
+ ATMEL_LCDC(PE, DATA8) | ATMEL_LCDC(PE, DATA9) | \
+ ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) | \
+ ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PD, DATA13) | \
+ ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) | \
+ ATMEL_LCDC(PE, DATA16) | ATMEL_LCDC(PE, DATA17) | \
+ ATMEL_LCDC(PE, DATA18) | ATMEL_LCDC(PE, DATA19) | \
+ ATMEL_LCDC(PE, DATA20) | ATMEL_LCDC(PE, DATA21) | \
+ ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_PRI_15B_DATA ( \
+ ATMEL_LCDC(PC, DATA0) | ATMEL_LCDC(PC, DATA1) | \
+ ATMEL_LCDC(PC, DATA2) | ATMEL_LCDC(PC, DATA3) | \
+ ATMEL_LCDC(PC, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PD, DATA8) | ATMEL_LCDC(PD, DATA9) | \
+ ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) | \
+ ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA16) | \
+ ATMEL_LCDC(PD, DATA17) | ATMEL_LCDC(PD, DATA18) | \
+ ATMEL_LCDC(PD, DATA19) | ATMEL_LCDC(PD, DATA20))
+
+#define ATMEL_LCDC_ALT_15B_DATA ( \
+ ATMEL_LCDC(PE, DATA0) | ATMEL_LCDC(PE, DATA1) | \
+ ATMEL_LCDC(PE, DATA2) | ATMEL_LCDC(PE, DATA3) | \
+ ATMEL_LCDC(PE, DATA4) | ATMEL_LCDC(PC, DATA5) | \
+ ATMEL_LCDC(PE, DATA8) | ATMEL_LCDC(PE, DATA9) | \
+ ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) | \
+ ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PE, DATA16) | \
+ ATMEL_LCDC(PE, DATA17) | ATMEL_LCDC(PE, DATA18) | \
+ ATMEL_LCDC(PE, DATA19) | ATMEL_LCDC(PE, DATA20))
+
+#define ATMEL_LCDC_PRI_CONTROL ( \
+ ATMEL_LCDC(PC, CC) | ATMEL_LCDC(PC, DVAL) | \
+ ATMEL_LCDC(PC, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_ALT_CONTROL ( \
+ ATMEL_LCDC(PE, CC) | ATMEL_LCDC(PE, DVAL) | \
+ ATMEL_LCDC(PE, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_CONTROL ( \
+ ATMEL_LCDC(PC, HSYNC) | ATMEL_LCDC(PC, VSYNC) | \
+ ATMEL_LCDC(PC, PCLK))
+
+#define ATMEL_LCDC_PRI_24BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_24B_DATA)
+
+#define ATMEL_LCDC_ALT_24BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_24B_DATA)
+
+#define ATMEL_LCDC_PRI_15BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_15B_DATA)
+
+#define ATMEL_LCDC_ALT_15BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_15B_DATA)
+
#endif /* __ASM_ARCH_AT32AP700X_H__ */
diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
index e60e9076544..c48386d66bc 100644
--- a/arch/avr32/mach-at32ap/include/mach/board.h
+++ b/arch/avr32/mach-at32ap/include/mach/board.h
@@ -43,7 +43,7 @@ struct atmel_lcdfb_info;
struct platform_device *
at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
unsigned long fbmem_start, unsigned long fbmem_len,
- unsigned int pin_config);
+ u64 pin_mask);
struct usba_platform_data;
struct platform_device *
diff --git a/arch/avr32/mach-at32ap/include/mach/io.h b/arch/avr32/mach-at32ap/include/mach/io.h
index 4ec6abc68ea..22ea79b7405 100644
--- a/arch/avr32/mach-at32ap/include/mach/io.h
+++ b/arch/avr32/mach-at32ap/include/mach/io.h
@@ -1,8 +1,7 @@
#ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
#define __ASM_AVR32_ARCH_AT32AP_IO_H
-/* For "bizarre" halfword swapping */
-#include <linux/byteorder/swabb.h>
+#include <linux/swab.h>
#if defined(CONFIG_AP700X_32_BIT_SMC)
# define __swizzle_addr_b(addr) (addr ^ 3UL)
diff --git a/arch/avr32/mach-at32ap/include/mach/portmux.h b/arch/avr32/mach-at32ap/include/mach/portmux.h
index b1abe6b4e4e..21c79373b53 100644
--- a/arch/avr32/mach-at32ap/include/mach/portmux.h
+++ b/arch/avr32/mach-at32ap/include/mach/portmux.h
@@ -21,9 +21,10 @@
#define AT32_GPIOF_DEGLITCH 0x00000008 /* (IN) Filter glitches */
#define AT32_GPIOF_MULTIDRV 0x00000010 /* Enable multidriver option */
-void at32_select_periph(unsigned int pin, unsigned int periph,
- unsigned long flags);
+void at32_select_periph(unsigned int port, unsigned int pin,
+ unsigned int periph, unsigned long flags);
void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_deselect_pin(unsigned int pin);
void at32_reserve_pin(unsigned int pin);
#endif /* __ASM_ARCH_PORTMUX_H__ */
diff --git a/arch/avr32/mach-at32ap/pdc.c b/arch/avr32/mach-at32ap/pdc.c
index 1040bda4fda..61ab15aae97 100644
--- a/arch/avr32/mach-at32ap/pdc.c
+++ b/arch/avr32/mach-at32ap/pdc.c
@@ -35,7 +35,6 @@ static int __init pdc_probe(struct platform_device *pdev)
}
static struct platform_driver pdc_driver = {
- .probe = pdc_probe,
.driver = {
.name = "pdc",
},
@@ -43,6 +42,6 @@ static struct platform_driver pdc_driver = {
static int __init pdc_init(void)
{
- return platform_driver_register(&pdc_driver);
+ return platform_driver_probe(&pdc_driver, pdc_probe);
}
arch_initcall(pdc_init);
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 405ee6bad4c..ed81a8bcb22 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -50,35 +50,48 @@ static struct pio_device *gpio_to_pio(unsigned int gpio)
}
/* Pin multiplexing API */
+static DEFINE_SPINLOCK(pio_lock);
-void __init at32_select_periph(unsigned int pin, unsigned int periph,
- unsigned long flags)
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
+ unsigned int periph, unsigned long flags)
{
struct pio_device *pio;
- unsigned int pin_index = pin & 0x1f;
- u32 mask = 1 << pin_index;
- pio = gpio_to_pio(pin);
+ /* assign and verify pio */
+ pio = gpio_to_pio(port);
if (unlikely(!pio)) {
- printk("pio: invalid pin %u\n", pin);
+ printk(KERN_WARNING "pio: invalid port %u\n", port);
goto fail;
}
- if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
- || gpiochip_is_requested(&pio->chip, pin_index))) {
- printk("%s: pin %u is busy\n", pio->name, pin_index);
+ /* Test if any of the requested pins is already muxed */
+ spin_lock(&pio_lock);
+ if (unlikely(pio->pinmux_mask & pin_mask)) {
+ printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
+ pio->name, pin_mask, pio->pinmux_mask & pin_mask);
+ spin_unlock(&pio_lock);
goto fail;
}
- pio_writel(pio, PUER, mask);
+ pio->pinmux_mask |= pin_mask;
+
+ /* enable pull ups */
+ pio_writel(pio, PUER, pin_mask);
+
+ /* select either peripheral A or B */
if (periph)
- pio_writel(pio, BSR, mask);
+ pio_writel(pio, BSR, pin_mask);
else
- pio_writel(pio, ASR, mask);
+ pio_writel(pio, ASR, pin_mask);
+
+ /* enable peripheral control */
+ pio_writel(pio, PDR, pin_mask);
- pio_writel(pio, PDR, mask);
+ /* Disable pull ups if not requested. */
if (!(flags & AT32_GPIOF_PULLUP))
- pio_writel(pio, PUDR, mask);
+ pio_writel(pio, PUDR, pin_mask);
+
+ spin_unlock(&pio_lock);
return;
@@ -134,6 +147,25 @@ fail:
dump_stack();
}
+/*
+ * Undo a previous pin reservation. Will not affect the hardware
+ * configuration.
+ */
+void at32_deselect_pin(unsigned int pin)
+{
+ struct pio_device *pio;
+ unsigned int pin_index = pin & 0x1f;
+
+ pio = gpio_to_pio(pin);
+ if (unlikely(!pio)) {
+ printk("pio: invalid pin %u\n", pin);
+ dump_stack();
+ return;
+ }
+
+ clear_bit(pin_index, &pio->pinmux_mask);
+}
+
/* Reserve a pin, preventing anyone else from changing its configuration. */
void __init at32_reserve_pin(unsigned int pin)
{
@@ -382,7 +414,6 @@ static int __init pio_probe(struct platform_device *pdev)
}
static struct platform_driver pio_driver = {
- .probe = pio_probe,
.driver = {
.name = "pio",
},
@@ -390,7 +421,7 @@ static struct platform_driver pio_driver = {
static int __init pio_init(void)
{
- return platform_driver_register(&pio_driver);
+ return platform_driver_probe(&pio_driver, pio_probe);
}
postcore_initcall(pio_init);
diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
index 1fe81c3c1e8..e0eb520e028 100644
--- a/arch/avr32/oprofile/Makefile
+++ b/arch/avr32/oprofile/Makefile
@@ -5,4 +5,4 @@ oprofile-y := $(addprefix ../../../drivers/oprofile/, \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o \
timer_int.o)
-oprofile-y += op_model_avr32.o
+oprofile-y += op_model_avr32.o backtrace.o
diff --git a/arch/avr32/oprofile/backtrace.c b/arch/avr32/oprofile/backtrace.c
new file mode 100644
index 00000000000..75d9ad6f99c
--- /dev/null
+++ b/arch/avr32/oprofile/backtrace.c
@@ -0,0 +1,81 @@
+/*
+ * AVR32 specific backtracing code for oprofile
+ *
+ * Copyright 2008 Weinmann GmbH
+ *
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Based on i386 oprofile backtrace code by John Levon and David Smith
+ *
+ * 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/oprofile.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+
+/* The first two words of each frame on the stack look like this if we have
+ * frame pointers */
+struct frame_head {
+ unsigned long lr;
+ struct frame_head *fp;
+};
+
+/* copied from arch/avr32/kernel/process.c */
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+ return (p > (unsigned long)tinfo)
+ && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+/* copied from arch/x86/oprofile/backtrace.c */
+static struct frame_head *dump_user_backtrace(struct frame_head *head)
+{
+ struct frame_head bufhead[2];
+
+ /* Also check accessibility of one struct frame_head beyond */
+ if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+ return NULL;
+ if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+ return NULL;
+
+ oprofile_add_trace(bufhead[0].lr);
+
+ /* frame pointers should strictly progress back up the stack
+ * (towards higher addresses) */
+ if (bufhead[0].fp <= head)
+ return NULL;
+
+ return bufhead[0].fp;
+}
+
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+ /* Get first frame pointer */
+ struct frame_head *head = (struct frame_head *)(regs->r7);
+
+ if (!user_mode(regs)) {
+#ifdef CONFIG_FRAME_POINTER
+ /*
+ * Traverse the kernel stack from frame to frame up to
+ * "depth" steps.
+ */
+ while (depth-- && valid_stack_ptr(task_thread_info(current),
+ (unsigned long)head)) {
+ oprofile_add_trace(head->lr);
+ if (head->fp <= head)
+ break;
+ head = head->fp;
+ }
+#endif
+ } else {
+ /* Assume we have frame pointers in user mode process */
+ while (depth-- && head)
+ head = dump_user_backtrace(head);
+ }
+}
+
+
diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
index df42325c7f8..a3e9b3c4845 100644
--- a/arch/avr32/oprofile/op_model_avr32.c
+++ b/arch/avr32/oprofile/op_model_avr32.c
@@ -22,6 +22,8 @@
#define AVR32_PERFCTR_IRQ_GROUP 0
#define AVR32_PERFCTR_IRQ_LINE 1
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
+
enum { PCCNT, PCNT0, PCNT1, NR_counter };
struct avr32_perf_counter {
@@ -223,6 +225,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
memcpy(ops, &avr32_perf_counter_ops,
sizeof(struct oprofile_operations));
+ ops->backtrace = avr32_backtrace;
+
printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
return 0;
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 4154ff1101f..8102c79aaa9 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -162,16 +162,28 @@ config BF549
config BF561
bool "BF561"
help
- Not Supported Yet - Work in progress - BF561 Processor Support.
+ BF561 Processor Support.
endchoice
+config BF_REV_MIN
+ int
+ default 0 if (BF52x || BF54x)
+ default 2 if (BF537 || BF536 || BF534)
+ default 3 if (BF561 ||BF533 || BF532 || BF531)
+
+config BF_REV_MAX
+ int
+ default 2 if (BF52x || BF54x)
+ default 3 if (BF537 || BF536 || BF534)
+ default 5 if (BF561)
+ default 6 if (BF533 || BF532 || BF531)
+
choice
prompt "Silicon Rev"
- default BF_REV_0_1 if BF527
- default BF_REV_0_2 if BF537
- default BF_REV_0_3 if BF533
- default BF_REV_0_0 if BF549
+ default BF_REV_0_1 if (BF52x || BF54x)
+ default BF_REV_0_2 if (BF534 || BF536 || BF537)
+ default BF_REV_0_3 if (BF531 || BF532 || BF533 || BF561)
config BF_REV_0_0
bool "0.0"
@@ -183,7 +195,7 @@ config BF_REV_0_1
config BF_REV_0_2
bool "0.2"
- depends on (BF537 || BF536 || BF534)
+ depends on (BF52x || BF537 || BF536 || BF534 || BF54x)
config BF_REV_0_3
bool "0.3"
@@ -197,6 +209,10 @@ config BF_REV_0_5
bool "0.5"
depends on (BF561 || BF533 || BF532 || BF531)
+config BF_REV_0_6
+ bool "0.6"
+ depends on (BF533 || BF532 || BF531)
+
config BF_REV_ANY
bool "any"
@@ -249,7 +265,7 @@ config MEM_MT48LC8M32B2B5_7
config MEM_MT48LC32M16A2TG_75
bool
- depends on (BFIN527_EZKIT || BFIN532_IP0X || BLACKSTAMP)
+ depends on (BFIN527_EZKIT || BFIN532_IP0X || BLACKSTAMP || BFIN526_EZBRD)
default y
source "arch/blackfin/mach-bf527/Kconfig"
@@ -286,13 +302,20 @@ config BOOT_LOAD
memory region is used to capture NULL pointer references as well
as some core kernel functions.
+config ROM_BASE
+ hex "Kernel ROM Base"
+ default "0x20040000"
+ range 0x20000000 0x20400000 if !(BF54x || BF561)
+ range 0x20000000 0x30000000 if (BF54x || BF561)
+ help
+
comment "Clock/PLL Setup"
config CLKIN_HZ
int "Frequency of the crystal on the board in Hz"
default "11059200" if BFIN533_STAMP
default "27000000" if BFIN533_EZKIT
- default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP)
+ default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD)
default "30000000" if BFIN561_EZKIT
default "24576000" if PNAV10
default "10000000" if BFIN532_IP0X
@@ -332,7 +355,7 @@ config VCO_MULT
default "22" if BFIN533_BLUETECHNIX_CM
default "20" if (BFIN537_BLUETECHNIX_CM || BFIN527_BLUETECHNIX_CM || BFIN561_BLUETECHNIX_CM)
default "20" if BFIN561_EZKIT
- default "16" if (H8606_HVSISTEMAS || BLACKSTAMP)
+ default "16" if (H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD)
help
This controls the frequency of the on-chip PLL. This can be between 1 and 64.
PLL Frequency = (Crystal Frequency) * (this setting)
@@ -368,14 +391,6 @@ config SCLK_DIV
This can be between 1 and 15
System Clock = (PLL frequency) / (this setting)
-config MAX_MEM_SIZE
- int "Max SDRAM Memory Size in MBytes"
- depends on !MPU
- default 512
- help
- This is the max memory size that the kernel will create CPLB
- tables for. Your system will not be able to handle any more.
-
choice
prompt "DDR SDRAM Chip Type"
depends on BFIN_KERNEL_CLOCK
@@ -389,6 +404,14 @@ config MEM_MT46V32M16_5B
bool "MT46V32M16_5B"
endchoice
+config MAX_MEM_SIZE
+ int "Max SDRAM Memory Size in MBytes"
+ depends on !MPU
+ default 512
+ help
+ This is the max memory size that the kernel will create CPLB
+ tables for. Your system will not be able to handle any more.
+
#
# Max & Min Speeds for various Chips
#
@@ -455,8 +478,6 @@ config CYCLES_CLOCKSOURCE
source kernel/time/Kconfig
-comment "Memory Setup"
-
comment "Misc"
choice
@@ -622,6 +643,15 @@ config CPLB_SWITCH_TAB_L1
If enabled, the CPLB Switch Tables are linked
into L1 data memory. (less latency)
+config APP_STACK_L1
+ bool "Support locating application stack in L1 Scratch Memory"
+ default y
+ help
+ If enabled the application stack can be located in L1
+ scratch memory (less latency).
+
+ Currently only works with FLAT binaries.
+
comment "Speed Optimizations"
config BFIN_INS_LOWOVERHEAD
bool "ins[bwl] low overhead, higher interrupt latency"
@@ -755,6 +785,13 @@ config BFIN_WT
endchoice
+config BFIN_L2_CACHEABLE
+ bool "Cache L2 SRAM"
+ depends on (BFIN_DCACHE || BFIN_ICACHE) && (BF54x || BF561)
+ default n
+ help
+ Select to make L2 SRAM cacheable in L1 data and instruction cache.
+
config MPU
bool "Enable the memory protection unit (EXPERIMENTAL)"
default n
diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug
index c468624d55f..3ad25983ec9 100644
--- a/arch/blackfin/Kconfig.debug
+++ b/arch/blackfin/Kconfig.debug
@@ -2,6 +2,22 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
+config HAVE_ARCH_KGDB
+ def_bool y
+
+config DEBUG_VERBOSE
+ bool "Verbose fault messages"
+ default y
+ select PRINTK
+ help
+ When a program crashes due to an exception, or the kernel detects
+ an internal error, the kernel can print a not so brief message
+ explaining what the problem was. This debugging information is
+ useful to developers and kernel hackers when tracking down problems,
+ but mostly meaningless to other people. This is always helpful for
+ debugging but serves no purpose on a production system.
+ Most people should say N here.
+
config DEBUG_MMRS
bool "Generate Blackfin MMR tree"
select DEBUG_FS
@@ -22,6 +38,44 @@ config DEBUG_HWERR
hardware error interrupts and need to know where they are coming
from.
+config DEBUG_DOUBLEFAULT
+ bool "Debug Double Faults"
+ default n
+ help
+ If an exception is caused while executing code within the exception
+ handler, the NMI handler, the reset vector, or in emulator mode,
+ a double fault occurs. On the Blackfin, this is a unrecoverable
+ event. You have two options:
+ - RESET exactly when double fault occurs. The excepting
+ instruction address is stored in RETX, where the next kernel
+ boot will print it out.
+ - Print debug message. This is much more error prone, although
+ easier to handle. It is error prone since:
+ - The excepting instruction is not committed.
+ - All writebacks from the instruction are prevented.
+ - The generated exception is not taken.
+ - The EXCAUSE field is updated with an unrecoverable event
+ The only way to check this is to see if EXCAUSE contains the
+ unrecoverable event value at every exception return. By selecting
+ this option, you are skipping over the faulting instruction, and
+ hoping things stay together enough to print out a debug message.
+
+ This does add a little kernel code, but is the only method to debug
+ double faults - if unsure say "Y"
+
+choice
+ prompt "Double Fault Failure Method"
+ default DEBUG_DOUBLEFAULT_PRINT
+ depends on DEBUG_DOUBLEFAULT
+
+config DEBUG_DOUBLEFAULT_PRINT
+ bool "Print"
+
+config DEBUG_DOUBLEFAULT_RESET
+ bool "Reset"
+
+endchoice
+
config DEBUG_ICACHE_CHECK
bool "Check Instruction cache coherency"
depends on DEBUG_KERNEL
@@ -143,6 +197,7 @@ config DEBUG_BFIN_NO_KERN_HWTRACE
config EARLY_PRINTK
bool "Early printk"
default n
+ select SERIAL_CORE_CONSOLE
help
This option enables special console drivers which allow the kernel
to print messages very early in the bootup process.
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
index eac0533d6e4..6bf50977850 100644
--- a/arch/blackfin/Makefile
+++ b/arch/blackfin/Makefile
@@ -67,6 +67,7 @@ rev-$(CONFIG_BF_REV_0_2) := 0.2
rev-$(CONFIG_BF_REV_0_3) := 0.3
rev-$(CONFIG_BF_REV_0_4) := 0.4
rev-$(CONFIG_BF_REV_0_5) := 0.5
+rev-$(CONFIG_BF_REV_0_6) := 0.6
rev-$(CONFIG_BF_REV_NONE) := none
rev-$(CONFIG_BF_REV_ANY) := any
diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig
new file mode 100644
index 00000000000..c33bf6f8381
--- /dev/null
+++ b/arch/blackfin/configs/BF526-EZBRD_defconfig
@@ -0,0 +1,1427 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26.3
+# Thu Aug 28 16:49:53 2008
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_HAVE_KPROBES is not set
+# CONFIG_HAVE_KRETPROBES is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
+# CONFIG_BF525 is not set
+CONFIG_BF526=y
+# CONFIG_BF527 is not set
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF547 is not set
+# CONFIG_BF548 is not set
+# CONFIG_BF549 is not set
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_1 is not set
+# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF52x=y
+CONFIG_MEM_MT48LC32M16A2TG_75=y
+# CONFIG_BFIN527_EZKIT is not set
+# CONFIG_BFIN527_BLUETECHNIX_CM is not set
+CONFIG_BFIN526_EZBRD=y
+
+#
+# BF527 Specific Configuration
+#
+
+#
+# Alternative Multiplexing Scheme
+#
+# CONFIG_BF527_SPORT0_PORTF is not set
+CONFIG_BF527_SPORT0_PORTG=y
+CONFIG_BF527_SPORT0_TSCLK_PG10=y
+# CONFIG_BF527_SPORT0_TSCLK_PG14 is not set
+CONFIG_BF527_UART1_PORTF=y
+# CONFIG_BF527_UART1_PORTG is not set
+# CONFIG_BF527_NAND_D_PORTF is not set
+CONFIG_BF527_NAND_D_PORTH=y
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_DMA0_ERROR=7
+CONFIG_IRQ_DMAR0_BLK=7
+CONFIG_IRQ_DMAR1_BLK=7
+CONFIG_IRQ_DMAR0_OVR=7
+CONFIG_IRQ_DMAR1_OVR=7
+CONFIG_IRQ_PPI_ERROR=7
+CONFIG_IRQ_MAC_ERROR=7
+CONFIG_IRQ_SPORT0_ERROR=7
+CONFIG_IRQ_SPORT1_ERROR=7
+CONFIG_IRQ_UART0_ERROR=7
+CONFIG_IRQ_UART1_ERROR=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_OPTSEC=11
+CONFIG_IRQ_CNT=11
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_PORTH_INTA=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_PORTH_INTB=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PORTG_INTA=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+CONFIG_IRQ_PORTF_INTA=13
+CONFIG_IRQ_PORTF_INTB=13
+CONFIG_IRQ_SPI_ERROR=7
+CONFIG_IRQ_NFC_ERROR=7
+CONFIG_IRQ_HDMA_ERROR=7
+CONFIG_IRQ_HDMA=7
+CONFIG_IRQ_USB_EINT=10
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Clock/PLL Setup
+#
+CONFIG_CLKIN_HZ=25000000
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+CONFIG_MAX_MEM_SIZE=512
+CONFIG_MAX_VCO_HZ=400000000
+CONFIG_MIN_VCO_HZ=50000000
+CONFIG_MAX_SCLK_HZ=133333333
+CONFIG_MIN_SCLK_HZ=27000000
+
+#
+# Kernel Timer/Scheduler
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+
+#
+# Memory Setup
+#
+
+#
+# Misc
+#
+CONFIG_BFIN_SCRATCH_REG_RETN=y
+# CONFIG_BFIN_SCRATCH_REG_RETE is not set
+# CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+# CONFIG_SCHEDULE_L1 is not set
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+# CONFIG_MEMSET_L1 is not set
+# CONFIG_MEMCPY_L1 is not set
+# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+
+#
+# Speed Optimizations
+#
+CONFIG_BFIN_INS_LOWOVERHEAD=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
+CONFIG_BFIN_GPTIMERS=y
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_4M is not set
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BFIN_ICACHE=y
+CONFIG_BFIN_DCACHE=y
+# CONFIG_BFIN_DCACHE_BANKA is not set
+# CONFIG_BFIN_ICACHE_LOCK is not set
+CONFIG_BFIN_WB=y
+# CONFIG_BFIN_WT is not set
+# CONFIG_MPU is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMGCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x5554
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0xFFC0
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_UCLINUX is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_BFIN=m
+CONFIG_BFIN_NAND_BASE=0x20212000
+CONFIG_BFIN_NAND_CLE=2
+CONFIG_BFIN_NAND_ALE=1
+CONFIG_BFIN_NAND_READY=3
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+CONFIG_BFIN_MAC_RMII=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_TWI_KEYPAD is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BFIN_SIMPLE_TIMER is not set
+# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_TWI_LCD is not set
+CONFIG_SIMPLE_GPIO=m
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+# CONFIG_SERIAL_BFIN_UART0 is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_AD5252 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BFIN=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_BFIN_WDT=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# SPI devices
+#
+
+#
+# ALSA Blackfin devices
+#
+# CONFIG_SND_BLACKFIN_AD1836 is not set
+# CONFIG_SND_BFIN_AD73311 is not set
+# CONFIG_SND_BFIN_AD73322 is not set
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+CONFIG_SND_SOC=m
+CONFIG_SND_BF5XX_I2S=m
+CONFIG_SND_BF5XX_SOC_SSM2602=m
+# CONFIG_SND_BF5XX_AC97 is not set
+CONFIG_SND_BF5XX_SOC_SPORT=m
+CONFIG_SND_BF5XX_SOC_I2S=m
+CONFIG_SND_BF5XX_SPORT_NUM=0
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
+CONFIG_SND_SOC_SSM2602=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_OTG_BLACKLIST_HUB=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# Blackfin high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+CONFIG_MUSB_PIO_ONLY=y
+CONFIG_USB_MUSB_LOGLEVEL=0
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_BFIN=y
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_MMRS=y
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+CONFIG_DEBUG_BFIN_HWTRACE_ON=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_OFF=y
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE is not set
+# CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_TWO is not set
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION=0
+# CONFIG_DEBUG_BFIN_HWTRACE_EXPAND is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig
index ba0bee90b7e..1fc31f1b762 100644
--- a/arch/blackfin/configs/H8606_defconfig
+++ b/arch/blackfin/configs/H8606_defconfig
@@ -1,6 +1,6 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.14
#
# CONFIG_MMU is not set
# CONFIG_FPU is not set
@@ -192,7 +192,7 @@ CONFIG_CLKIN_HZ=25000000
# CONFIG_BFIN_KERNEL_CLOCK is not set
CONFIG_MAX_VCO_HZ=400000000
CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
CONFIG_MIN_SCLK_HZ=27000000
#
@@ -516,7 +516,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
#
# CONFIG_MTD_DATAFLASH is not set
CONFIG_MTD_M25P80=y
-CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_M25PXX_USE_FAST_READ is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
@@ -635,25 +635,25 @@ CONFIG_INPUT=y
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
-CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set
#
# Input Device Drivers
#
-# CONFIG_INPUT_KEYBOARD is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_ATI_REMOTE is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_BF53X_PFBUTTONS is not set
+# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
@@ -681,7 +681,15 @@ CONFIG_BFIN_TIMER_LATENCY=y
#
# Serial drivers
#
-# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
#
# Non-8250 serial port support
diff --git a/arch/blackfin/include/asm/a.out.h b/arch/blackfin/include/asm/a.out.h
deleted file mode 100644
index 6c3d652ebd3..00000000000
--- a/arch/blackfin/include/asm/a.out.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __BFIN_A_OUT_H__
-#define __BFIN_A_OUT_H__
-
-struct exec {
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif /* __BFIN_A_OUT_H__ */
diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h
index 7ba70de66f2..56dcb0a2d24 100644
--- a/arch/blackfin/include/asm/bfin-global.h
+++ b/arch/blackfin/include/asm/bfin-global.h
@@ -63,7 +63,6 @@ extern void bfin_dcache_init(void);
extern void init_exception_vectors(void);
extern void program_IAR(void);
-extern void bfin_reset(void);
extern asmlinkage void lower_to_irq14(void);
extern asmlinkage void bfin_return_from_exception(void);
extern asmlinkage void evt14_softirq(void);
@@ -92,6 +91,8 @@ extern int sram_free(const void*);
extern void *sram_alloc_with_lsl(size_t, unsigned long);
extern int sram_free_with_lsl(const void*);
+extern void *isram_memcpy(void *dest, const void *src, size_t n);
+
extern const char bfin_board_name[];
extern unsigned long bfin_sic_iwr[];
@@ -104,7 +105,7 @@ extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
_stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
_ebss_l2[], _l2_lma_start[];
-/* only used when CONFIG_MTD_UCLINUX */
+/* only used when MTD_UCLINUX */
extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
#ifdef CONFIG_BFIN_ICACHE_LOCK
diff --git a/arch/blackfin/include/asm/bfrom.h b/arch/blackfin/include/asm/bfrom.h
new file mode 100644
index 00000000000..cfe8024c3b2
--- /dev/null
+++ b/arch/blackfin/include/asm/bfrom.h
@@ -0,0 +1,85 @@
+/* Blackfin on-chip ROM API
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BFROM_H__
+#define __BFROM_H__
+
+#include <linux/types.h>
+
+/* Possible syscontrol action flags */
+#define SYSCTRL_READ 0x00000000 /* read registers */
+#define SYSCTRL_WRITE 0x00000001 /* write registers */
+#define SYSCTRL_SYSRESET 0x00000002 /* perform system reset */
+#define SYSCTRL_CORERESET 0x00000004 /* perform core reset */
+#define SYSCTRL_SOFTRESET 0x00000006 /* perform core and system reset */
+#define SYSCTRL_VRCTL 0x00000010 /* read/write VR_CTL register */
+#define SYSCTRL_EXTVOLTAGE 0x00000020 /* VDDINT supplied externally */
+#define SYSCTRL_INTVOLTAGE 0x00000000 /* VDDINT generated by on-chip regulator */
+#define SYSCTRL_OTPVOLTAGE 0x00000040 /* For Factory Purposes Only */
+#define SYSCTRL_PLLCTL 0x00000100 /* read/write PLL_CTL register */
+#define SYSCTRL_PLLDIV 0x00000200 /* read/write PLL_DIV register */
+#define SYSCTRL_LOCKCNT 0x00000400 /* read/write PLL_LOCKCNT register */
+#define SYSCTRL_PLLSTAT 0x00000800 /* read/write PLL_STAT register */
+
+typedef struct ADI_SYSCTRL_VALUES {
+ uint16_t uwVrCtl;
+ uint16_t uwPllCtl;
+ uint16_t uwPllDiv;
+ uint16_t uwPllLockCnt;
+ uint16_t uwPllStat;
+} ADI_SYSCTRL_VALUES;
+
+static uint32_t (* const bfrom_SysControl)(uint32_t action_flags, ADI_SYSCTRL_VALUES *power_settings, void *reserved) = (void *)0xEF000038;
+
+/* We need a dedicated function since we need to screw with the stack pointer
+ * when resetting. The on-chip ROM will save/restore registers on the stack
+ * when doing a system reset, so the stack cannot be outside of the chip.
+ */
+__attribute__((__noreturn__))
+static inline void bfrom_SoftReset(void *new_stack)
+{
+ while (1)
+ __asm__ __volatile__(
+ "sp = %[stack];"
+ "jump (%[bfrom_syscontrol]);"
+ : : [bfrom_syscontrol] "p"(bfrom_SysControl),
+ "q0"(SYSCTRL_SOFTRESET),
+ "q1"(0),
+ "q2"(NULL),
+ [stack] "p"(new_stack)
+ );
+}
+
+/* OTP Functions */
+static uint32_t (* const bfrom_OtpCommand)(uint32_t command, uint32_t value) = (void *)0xEF000018;
+static uint32_t (* const bfrom_OtpRead)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001A;
+static uint32_t (* const bfrom_OtpWrite)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001C;
+
+/* otp command: defines for "command" */
+#define OTP_INIT 0x00000001
+#define OTP_CLOSE 0x00000002
+
+/* otp read/write: defines for "flags" */
+#define OTP_LOWER_HALF 0x00000000 /* select upper/lower 64-bit half (bit 0) */
+#define OTP_UPPER_HALF 0x00000001
+#define OTP_NO_ECC 0x00000010 /* do not use ECC */
+#define OTP_LOCK 0x00000020 /* sets page protection bit for page */
+#define OTP_CHECK_FOR_PREV_WRITE 0x00000080
+
+/* Return values for all functions */
+#define OTP_SUCCESS 0x00000000
+#define OTP_MASTER_ERROR 0x001
+#define OTP_WRITE_ERROR 0x003
+#define OTP_READ_ERROR 0x005
+#define OTP_ACC_VIO_ERROR 0x009
+#define OTP_DATA_MULT_ERROR 0x011
+#define OTP_ECC_MULT_ERROR 0x021
+#define OTP_PREV_WR_ERROR 0x041
+#define OTP_DATA_SB_WARN 0x100
+#define OTP_ECC_SB_WARN 0x200
+
+#endif
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index d81a77545a0..5ef9e35e9c3 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -30,8 +30,6 @@
#ifndef _BLACKFIN_CACHEFLUSH_H
#define _BLACKFIN_CACHEFLUSH_H
-#include <asm/cplb.h>
-
extern void blackfin_icache_dcache_flush_range(unsigned int, unsigned int);
extern void blackfin_icache_flush_range(unsigned int, unsigned int);
extern void blackfin_dcache_flush_range(unsigned int, unsigned int);
diff --git a/arch/blackfin/include/asm/cplb.h b/arch/blackfin/include/asm/cplb.h
index 05d6f05fb74..9e8b4035fce 100644
--- a/arch/blackfin/include/asm/cplb.h
+++ b/arch/blackfin/include/asm/cplb.h
@@ -55,7 +55,13 @@
#endif
#define L1_DMEMORY (CPLB_LOCK | CPLB_COMMON)
-#define L2_MEMORY (CPLB_COMMON)
+#ifdef CONFIG_BFIN_L2_CACHEABLE
+#define L2_IMEMORY (SDRAM_IGENERIC)
+#define L2_DMEMORY (SDRAM_DGENERIC)
+#else
+#define L2_IMEMORY (CPLB_COMMON)
+#define L2_DMEMORY (CPLB_COMMON)
+#endif
#define SDRAM_DNON_CHBL (CPLB_COMMON)
#define SDRAM_EBIU (CPLB_COMMON)
#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
diff --git a/arch/blackfin/include/asm/cplbinit.h b/arch/blackfin/include/asm/cplbinit.h
index 0eb1c1b685a..d179b747ff0 100644
--- a/arch/blackfin/include/asm/cplbinit.h
+++ b/arch/blackfin/include/asm/cplbinit.h
@@ -90,6 +90,20 @@ extern u_long dpdt_swapcount_table[];
extern unsigned long reserved_mem_dcache_on;
extern unsigned long reserved_mem_icache_on;
-extern void generate_cpl_tables(void);
+extern void generate_cplb_tables(void);
+
+static inline int bfin_addr_dcachable(unsigned long addr)
+{
+#ifdef CONFIG_BFIN_DCACHE
+ if (addr < (_ramend - DMA_UNCACHED_REGION))
+ return 1;
+#endif
+
+ if (reserved_mem_dcache_on &&
+ addr >= _ramend && addr < physical_mem_end)
+ return 1;
+
+ return 0;
+}
#endif
diff --git a/arch/blackfin/include/asm/cpumask.h b/arch/blackfin/include/asm/cpumask.h
deleted file mode 100644
index b20a8e9012c..00000000000
--- a/arch/blackfin/include/asm/cpumask.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_BLACKFIN_CPUMASK_H
-#define _ASM_BLACKFIN_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_BLACKFIN_CPUMASK_H */
diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h
index 1a13c2fc366..ede748d67ef 100644
--- a/arch/blackfin/include/asm/dma-mapping.h
+++ b/arch/blackfin/include/asm/dma-mapping.h
@@ -80,4 +80,15 @@ extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
int nhwentries, enum dma_data_direction direction);
+static inline void dma_sync_single_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size,
+ enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+ dma_addr_t handle, size_t size,
+ enum dma_data_direction dir)
+{
+}
#endif /* _BLACKFIN_DMA_MAPPING_H */
diff --git a/arch/blackfin/include/asm/kgdb.h b/arch/blackfin/include/asm/kgdb.h
index 0f73847fd6b..26ebac6646d 100644
--- a/arch/blackfin/include/asm/kgdb.h
+++ b/arch/blackfin/include/asm/kgdb.h
@@ -124,9 +124,16 @@ enum regnames {
/* Number of bytes of registers. */
#define NUMREGBYTES BFIN_NUM_REGS*4
-#define BREAKPOINT() asm(" EXCPT 2;");
-#define BREAK_INSTR_SIZE 2
-#define HW_BREAKPOINT_NUM 6
+static inline void arch_kgdb_breakpoint(void)
+{
+ asm(" EXCPT 2;");
+}
+#define BREAK_INSTR_SIZE 2
+#define CACHE_FLUSH_IS_SAFE 1
+#define HW_INST_WATCHPOINT_NUM 6
+#define HW_WATCHPOINT_NUM 8
+#define TYPE_INST_WATCHPOINT 0
+#define TYPE_DATA_WATCHPOINT 1
/* Instruction watchpoint address control register bits mask */
#define WPPWR 0x1
@@ -163,10 +170,11 @@ enum regnames {
#define WPDAEN1 0x8
#define WPDCNTEN0 0x10
#define WPDCNTEN1 0x20
+
#define WPDSRC0 0xc0
-#define WPDACC0 0x300
+#define WPDACC0_OFFSET 8
#define WPDSRC1 0xc00
-#define WPDACC1 0x3000
+#define WPDACC1_OFFSET 12
/* Watchpoint status register bits mask */
#define STATIA0 0x1
@@ -178,7 +186,4 @@ enum regnames {
#define STATDA0 0x40
#define STATDA1 0x80
-extern void kgdb_print(const char *fmt, ...);
-extern void init_kgdb_uart(void);
-
#endif
diff --git a/arch/blackfin/include/asm/mmu_context.h b/arch/blackfin/include/asm/mmu_context.h
index 8529552a981..35593dda2a4 100644
--- a/arch/blackfin/include/asm/mmu_context.h
+++ b/arch/blackfin/include/asm/mmu_context.h
@@ -45,49 +45,12 @@ extern unsigned long l1_stack_len;
extern int l1sram_free(const void*);
extern void *l1sram_alloc_max(void*);
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-{
-}
-
-/* Called when creating a new context during fork() or execve(). */
-static inline int
-init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-{
-#ifdef CONFIG_MPU
- unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
- mm->context.page_rwx_mask = (unsigned long *)p;
- memset(mm->context.page_rwx_mask, 0,
- page_mask_nelts * 3 * sizeof(long));
-#endif
- return 0;
-}
-
static inline void free_l1stack(void)
{
nr_l1stack_tasks--;
if (nr_l1stack_tasks == 0)
l1sram_free(l1_stack_base);
}
-static inline void destroy_context(struct mm_struct *mm)
-{
- struct sram_list_struct *tmp;
-
- if (current_l1_stack_save == mm->context.l1_stack_save)
- current_l1_stack_save = NULL;
- if (mm->context.l1_stack_save)
- free_l1stack();
-
- while ((tmp = mm->context.sram_list)) {
- mm->context.sram_list = tmp->next;
- sram_free(tmp->addr);
- kfree(tmp);
- }
-#ifdef CONFIG_MPU
- if (current_rwx_mask == mm->context.page_rwx_mask)
- current_rwx_mask = NULL;
- free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
-#endif
-}
static inline unsigned long
alloc_l1stack(unsigned long length, unsigned long *stack_base)
@@ -134,6 +97,7 @@ static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_m
}
#endif
+#ifdef CONFIG_APP_STACK_L1
/* L1 stack switching. */
if (!next_mm->context.l1_stack_save)
return;
@@ -144,6 +108,7 @@ static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_m
}
current_l1_stack_save = next_mm->context.l1_stack_save;
memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+#endif
}
#ifdef CONFIG_MPU
@@ -180,4 +145,44 @@ static inline void update_protections(struct mm_struct *mm)
}
#endif
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/* Called when creating a new context during fork() or execve(). */
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+#ifdef CONFIG_MPU
+ unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
+ mm->context.page_rwx_mask = (unsigned long *)p;
+ memset(mm->context.page_rwx_mask, 0,
+ page_mask_nelts * 3 * sizeof(long));
+#endif
+ return 0;
+}
+
+static inline void destroy_context(struct mm_struct *mm)
+{
+ struct sram_list_struct *tmp;
+
+#ifdef CONFIG_APP_STACK_L1
+ if (current_l1_stack_save == mm->context.l1_stack_save)
+ current_l1_stack_save = 0;
+ if (mm->context.l1_stack_save)
+ free_l1stack();
+#endif
+
+ while ((tmp = mm->context.sram_list)) {
+ mm->context.sram_list = tmp->next;
+ sram_free(tmp->addr);
+ kfree(tmp);
+ }
+#ifdef CONFIG_MPU
+ if (current_rwx_mask == mm->context.page_rwx_mask)
+ current_rwx_mask = NULL;
+ free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
+#endif
+}
+
#endif
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h
index 6f3995b119d..e3e9b41fa8d 100644
--- a/arch/blackfin/include/asm/processor.h
+++ b/arch/blackfin/include/asm/processor.h
@@ -134,6 +134,12 @@ static inline uint32_t __pure bfin_revid(void)
return revid;
}
+static inline uint16_t __pure bfin_cpuid(void)
+{
+ return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12;
+
+}
+
static inline uint32_t __pure bfin_compiled_revid(void)
{
#if defined(CONFIG_BF_REV_0_0)
diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h
index a45a80e54ad..e3f086dc726 100644
--- a/arch/blackfin/include/asm/ptrace.h
+++ b/arch/blackfin/include/asm/ptrace.h
@@ -158,6 +158,8 @@ extern void show_regs(struct pt_regs *);
#define PT_SEQSTAT 8
#define PT_IPEND 4
+#define PT_ORIG_R0 208
+#define PT_ORIG_P0 212
#define PT_SYSCFG 216
#define PT_TEXT_ADDR 220
#define PT_TEXT_END_ADDR 224
diff --git a/arch/blackfin/include/asm/traps.h b/arch/blackfin/include/asm/traps.h
index f0e5f940d9c..34f7295fb07 100644
--- a/arch/blackfin/include/asm/traps.h
+++ b/arch/blackfin/include/asm/traps.h
@@ -59,6 +59,9 @@
level " or a 16-bit register is accessed with a 32-bit instruction.\n"
#define HWC_x3(level) \
"External Memory Addressing Error\n"
+#define EXC_0x04(level) \
+ "Unimplmented exception occured\n" \
+ level " - Maybe you forgot to install a custom exception handler?\n"
#define HWC_x12(level) \
"Performance Monitor Overflow\n"
#define HWC_x18(level) \
@@ -84,7 +87,7 @@
level " a particular processor implementation.\n"
#define EXC_0x22(level) \
"Illegal instruction combination\n" \
- level " - See section for multi-issue rules in the ADSP-BF53x Blackfin\n" \
+ level " - See section for multi-issue rules in the Blackfin\n" \
level " Processor Instruction Set Reference.\n"
#define EXC_0x23(level) \
"Data access CPLB protection violation\n" \
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
index 881afe9082c..9bb85dd5ccb 100644
--- a/arch/blackfin/kernel/asm-offsets.c
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -60,6 +60,7 @@ int main(void)
DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
/* offsets into the pt_regs */
+ DEFINE(PT_ORIG_R0, offsetof(struct pt_regs, orig_r0));
DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
DEFINE(PT_R0, offsetof(struct pt_regs, r0));
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 93229b3d6e3..339293d677c 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -117,15 +117,14 @@ int request_dma(unsigned int channel, char *device_id)
#ifdef CONFIG_BF54x
if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
- if (strncmp(device_id, "BFIN_UART", 9) == 0) {
- dma_ch[channel].regs->peripheral_map &= 0x0FFF;
- dma_ch[channel].regs->peripheral_map |=
+ unsigned int per_map;
+ per_map = dma_ch[channel].regs->peripheral_map & 0xFFF;
+ if (strncmp(device_id, "BFIN_UART", 9) == 0)
+ dma_ch[channel].regs->peripheral_map = per_map |
((channel - CH_UART2_RX + 0xC)<<12);
- } else {
- dma_ch[channel].regs->peripheral_map &= 0x0FFF;
- dma_ch[channel].regs->peripheral_map |=
+ else
+ dma_ch[channel].regs->peripheral_map = per_map |
((channel - CH_UART2_RX + 0x6)<<12);
- }
}
#endif
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index ecbd141e0ef..6e08f425bb4 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -231,14 +231,14 @@ inline int check_gpio(unsigned gpio)
}
#endif
-void gpio_error(unsigned gpio)
+static void gpio_error(unsigned gpio)
{
printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio);
}
static void set_label(unsigned short ident, const char *label)
{
- if (label && str_ident) {
+ if (label) {
strncpy(str_ident[ident].name, label,
RESOURCE_LABEL_SIZE);
str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0;
@@ -247,9 +247,6 @@ static void set_label(unsigned short ident, const char *label)
static char *get_label(unsigned short ident)
{
- if (!str_ident)
- return "UNKNOWN";
-
return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN");
}
@@ -260,7 +257,7 @@ static int cmp_label(unsigned short ident, const char *label)
printk(KERN_ERR "Please provide none-null label\n");
}
- if (label && str_ident)
+ if (label)
return strncmp(str_ident[ident].name,
label, strlen(label));
else
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
index 48060105346..55af729f849 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -36,7 +36,7 @@ struct cplb_entry dcplb_tbl[MAX_CPLBS];
int first_switched_icplb, first_switched_dcplb;
int first_mask_dcplb;
-void __init generate_cpl_tables(void)
+void __init generate_cplb_tables(void)
{
int i_d, i_i;
unsigned long addr;
@@ -83,8 +83,18 @@ void __init generate_cpl_tables(void)
dcplb_tbl[i_d].addr = L1_DATA_A_START;
dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
#endif
+#if L1_CODE_LENGTH > 0
icplb_tbl[i_i].addr = L1_CODE_START;
icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
+#endif
+
+ /* Cover L2 memory */
+#if L2_LENGTH > 0
+ dcplb_tbl[i_d].addr = L2_START;
+ dcplb_tbl[i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB;
+ icplb_tbl[i_i].addr = L2_START;
+ icplb_tbl[i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB;
+#endif
first_mask_dcplb = i_d;
first_switched_dcplb = i_d + (1 << page_mask_order);
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index 99f2831e296..5094677fd09 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -322,9 +322,11 @@ int cplb_hdr(int seqstat, struct pt_regs *regs)
void flush_switched_cplbs(void)
{
int i;
+ unsigned long flags;
nr_cplb_flush++;
+ local_irq_save(flags);
disable_icplb();
for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
icplb_tbl[i].data = 0;
@@ -338,6 +340,8 @@ void flush_switched_cplbs(void)
bfin_write32(DCPLB_DATA0 + i * 4, 0);
}
enable_dcplb();
+ local_irq_restore(flags);
+
}
void set_mask_dcplbs(unsigned long *masks)
@@ -345,10 +349,15 @@ void set_mask_dcplbs(unsigned long *masks)
int i;
unsigned long addr = (unsigned long)masks;
unsigned long d_data;
- current_rwx_mask = masks;
+ unsigned long flags;
- if (!masks)
+ if (!masks) {
+ current_rwx_mask = masks;
return;
+ }
+
+ local_irq_save(flags);
+ current_rwx_mask = masks;
d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
#ifdef CONFIG_BFIN_DCACHE
@@ -367,4 +376,5 @@ void set_mask_dcplbs(unsigned long *masks)
addr += PAGE_SIZE;
}
enable_dcplb();
+ local_irq_restore(flags);
}
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
index 728f708d398..301252e8444 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
@@ -168,8 +168,8 @@ static struct cplb_desc cplb_data[] = {
.end = L2_START + L2_LENGTH,
.psize = SIZE_1M,
.attr = SWITCH_T | I_CPLB | D_CPLB,
- .i_conf = L2_MEMORY,
- .d_conf = L2_MEMORY,
+ .i_conf = L2_IMEMORY,
+ .d_conf = L2_DMEMORY,
.valid = (L2_LENGTH > 0),
.name = "L2 Memory",
},
@@ -308,7 +308,7 @@ __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
}
}
-void __init generate_cpl_tables(void)
+void __init generate_cplb_tables(void)
{
u16 i, j, process;
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index 60f67f90fe3..1f4e3d2e090 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -35,6 +35,9 @@
extern struct console *bfin_earlyserial_init(unsigned int port,
unsigned int cflag);
#endif
+#ifdef CONFIG_BFIN_JTAG_COMM
+extern struct console *bfin_jc_early_init(void);
+#endif
static struct console *early_console;
@@ -142,6 +145,15 @@ int __init setup_early_printk(char *buf)
early_console = earlyserial_init(buf);
}
#endif
+
+#ifdef CONFIG_BFIN_JTAG_COMM
+ /* Check for Blackfin JTAG */
+ if (!strncmp(buf, "jtag", 4)) {
+ buf += 4;
+ early_console = bfin_jc_early_init();
+ }
+#endif
+
#ifdef CONFIG_FB
/* TODO: add framebuffer console support */
#endif
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
index a1f9641a642..b795a207742 100644
--- a/arch/blackfin/kernel/kgdb.c
+++ b/arch/blackfin/kernel/kgdb.c
@@ -1,32 +1,9 @@
/*
- * File: arch/blackfin/kernel/kgdb.c
- * Based on:
- * Author: Sonic Zhang
+ * arch/blackfin/kernel/kgdb.c - Blackfin kgdb pieces
*
- * Created:
- * Description:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Rev: $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
- *
- * Modified:
- * Copyright 2005-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/string.h>
@@ -39,24 +16,29 @@
#include <linux/kgdb.h>
#include <linux/console.h>
#include <linux/init.h>
-#include <linux/debugger.h>
#include <linux/errno.h>
#include <linux/irq.h>
+#include <linux/uaccess.h>
#include <asm/system.h>
#include <asm/traps.h>
#include <asm/blackfin.h>
+#include <asm/dma.h>
/* Put the error code here just in case the user cares. */
-int gdb_bf533errcode;
+int gdb_bfin_errcode;
/* Likewise, the vector number here (since GDB only gets the signal
number through the usual means, and that's not very specific). */
-int gdb_bf533vector = -1;
+int gdb_bfin_vector = -1;
#if KGDB_MAX_NO_CPUS != 8
#error change the definition of slavecpulocks
#endif
-void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+#ifdef CONFIG_BFIN_WDT
+# error "Please unselect blackfin watchdog driver before build KGDB."
+#endif
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
gdb_regs[BFIN_R0] = regs->r0;
gdb_regs[BFIN_R1] = regs->r1;
@@ -133,7 +115,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat;
}
-void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
regs->r0 = gdb_regs[BFIN_R0];
regs->r1 = gdb_regs[BFIN_R1];
@@ -199,171 +181,208 @@ struct hw_breakpoint {
unsigned int dataacc:2;
unsigned short count;
unsigned int addr;
-} breakinfo[HW_BREAKPOINT_NUM];
+} breakinfo[HW_WATCHPOINT_NUM];
-int kgdb_arch_init(void)
-{
- debugger_step = 0;
-
- kgdb_remove_all_hw_break();
- return 0;
-}
-
-int kgdb_set_hw_break(unsigned long addr)
+int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
{
int breakno;
- for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
- if (!breakinfo[breakno].occupied) {
+ int bfin_type;
+ int dataacc = 0;
+
+ switch (type) {
+ case BP_HARDWARE_BREAKPOINT:
+ bfin_type = TYPE_INST_WATCHPOINT;
+ break;
+ case BP_WRITE_WATCHPOINT:
+ dataacc = 1;
+ bfin_type = TYPE_DATA_WATCHPOINT;
+ break;
+ case BP_READ_WATCHPOINT:
+ dataacc = 2;
+ bfin_type = TYPE_DATA_WATCHPOINT;
+ break;
+ case BP_ACCESS_WATCHPOINT:
+ dataacc = 3;
+ bfin_type = TYPE_DATA_WATCHPOINT;
+ break;
+ default:
+ return -ENOSPC;
+ }
+
+ /* Becasue hardware data watchpoint impelemented in current
+ * Blackfin can not trigger an exception event as the hardware
+ * instrction watchpoint does, we ignaore all data watch point here.
+ * They can be turned on easily after future blackfin design
+ * supports this feature.
+ */
+ for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+ if (bfin_type == breakinfo[breakno].type
+ && !breakinfo[breakno].occupied) {
breakinfo[breakno].occupied = 1;
breakinfo[breakno].enabled = 1;
- breakinfo[breakno].type = 1;
breakinfo[breakno].addr = addr;
+ breakinfo[breakno].dataacc = dataacc;
+ breakinfo[breakno].count = 0;
return 0;
}
return -ENOSPC;
}
-int kgdb_remove_hw_break(unsigned long addr)
+int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
{
int breakno;
- for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
- if (breakinfo[breakno].addr == addr)
- memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint));
+ int bfin_type;
+
+ switch (type) {
+ case BP_HARDWARE_BREAKPOINT:
+ bfin_type = TYPE_INST_WATCHPOINT;
+ break;
+ case BP_WRITE_WATCHPOINT:
+ case BP_READ_WATCHPOINT:
+ case BP_ACCESS_WATCHPOINT:
+ bfin_type = TYPE_DATA_WATCHPOINT;
+ break;
+ default:
+ return 0;
+ }
+ for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+ if (bfin_type == breakinfo[breakno].type
+ && breakinfo[breakno].occupied
+ && breakinfo[breakno].addr == addr) {
+ breakinfo[breakno].occupied = 0;
+ breakinfo[breakno].enabled = 0;
+ }
return 0;
}
-void kgdb_remove_all_hw_break(void)
+void bfin_remove_all_hw_break(void)
{
- memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8);
-}
+ int breakno;
-/*
-void kgdb_show_info(void)
-{
- printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n",
- bfin_read_WPIA0(), bfin_read_WPIACNT0(),
- bfin_read_WPIACTL(), bfin_read_WPSTAT());
+ memset(breakinfo, 0, sizeof(struct hw_breakpoint)*HW_WATCHPOINT_NUM);
+
+ for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+ breakinfo[breakno].type = TYPE_INST_WATCHPOINT;
+ for (; breakno < HW_WATCHPOINT_NUM; breakno++)
+ breakinfo[breakno].type = TYPE_DATA_WATCHPOINT;
}
-*/
-void kgdb_correct_hw_break(void)
+void bfin_correct_hw_break(void)
{
int breakno;
- int correctit;
- uint32_t wpdactl = bfin_read_WPDACTL();
+ unsigned int wpiactl = 0;
+ unsigned int wpdactl = 0;
+ int enable_wp = 0;
+
+ for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+ if (breakinfo[breakno].enabled) {
+ enable_wp = 1;
- correctit = 0;
- for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) {
- if (breakinfo[breakno].type == 1) {
switch (breakno) {
case 0:
- if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) {
- correctit = 1;
- wpdactl &= ~(WPIREN01|EMUSW0);
- wpdactl |= WPIAEN0|WPICNTEN0;
- bfin_write_WPIA0(breakinfo[breakno].addr);
- bfin_write_WPIACNT0(breakinfo[breakno].skip);
- } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) {
- correctit = 1;
- wpdactl &= ~WPIAEN0;
- }
+ wpiactl |= WPIAEN0|WPICNTEN0;
+ bfin_write_WPIA0(breakinfo[breakno].addr);
+ bfin_write_WPIACNT0(breakinfo[breakno].count
+ + breakinfo->skip);
break;
-
case 1:
- if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) {
- correctit = 1;
- wpdactl &= ~(WPIREN01|EMUSW1);
- wpdactl |= WPIAEN1|WPICNTEN1;
- bfin_write_WPIA1(breakinfo[breakno].addr);
- bfin_write_WPIACNT1(breakinfo[breakno].skip);
- } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) {
- correctit = 1;
- wpdactl &= ~WPIAEN1;
- }
+ wpiactl |= WPIAEN1|WPICNTEN1;
+ bfin_write_WPIA1(breakinfo[breakno].addr);
+ bfin_write_WPIACNT1(breakinfo[breakno].count
+ + breakinfo->skip);
break;
-
case 2:
- if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) {
- correctit = 1;
- wpdactl &= ~(WPIREN23|EMUSW2);
- wpdactl |= WPIAEN2|WPICNTEN2;
- bfin_write_WPIA2(breakinfo[breakno].addr);
- bfin_write_WPIACNT2(breakinfo[breakno].skip);
- } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) {
- correctit = 1;
- wpdactl &= ~WPIAEN2;
- }
+ wpiactl |= WPIAEN2|WPICNTEN2;
+ bfin_write_WPIA2(breakinfo[breakno].addr);
+ bfin_write_WPIACNT2(breakinfo[breakno].count
+ + breakinfo->skip);
break;
-
case 3:
- if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) {
- correctit = 1;
- wpdactl &= ~(WPIREN23|EMUSW3);
- wpdactl |= WPIAEN3|WPICNTEN3;
- bfin_write_WPIA3(breakinfo[breakno].addr);
- bfin_write_WPIACNT3(breakinfo[breakno].skip);
- } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) {
- correctit = 1;
- wpdactl &= ~WPIAEN3;
- }
+ wpiactl |= WPIAEN3|WPICNTEN3;
+ bfin_write_WPIA3(breakinfo[breakno].addr);
+ bfin_write_WPIACNT3(breakinfo[breakno].count
+ + breakinfo->skip);
break;
case 4:
- if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) {
- correctit = 1;
- wpdactl &= ~(WPIREN45|EMUSW4);
- wpdactl |= WPIAEN4|WPICNTEN4;
- bfin_write_WPIA4(breakinfo[breakno].addr);
- bfin_write_WPIACNT4(breakinfo[breakno].skip);
- } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) {
- correctit = 1;
- wpdactl &= ~WPIAEN4;
- }
+ wpiactl |= WPIAEN4|WPICNTEN4;
+ bfin_write_WPIA4(breakinfo[breakno].addr);
+ bfin_write_WPIACNT4(breakinfo[breakno].count
+ + breakinfo->skip);
break;
case 5:
- if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) {
- correctit = 1;
- wpdactl &= ~(WPIREN45|EMUSW5);
- wpdactl |= WPIAEN5|WPICNTEN5;
- bfin_write_WPIA5(breakinfo[breakno].addr);
- bfin_write_WPIACNT5(breakinfo[breakno].skip);
- } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) {
- correctit = 1;
- wpdactl &= ~WPIAEN5;
- }
+ wpiactl |= WPIAEN5|WPICNTEN5;
+ bfin_write_WPIA5(breakinfo[breakno].addr);
+ bfin_write_WPIACNT5(breakinfo[breakno].count
+ + breakinfo->skip);
+ break;
+ case 6:
+ wpdactl |= WPDAEN0|WPDCNTEN0|WPDSRC0;
+ wpdactl |= breakinfo[breakno].dataacc
+ << WPDACC0_OFFSET;
+ bfin_write_WPDA0(breakinfo[breakno].addr);
+ bfin_write_WPDACNT0(breakinfo[breakno].count
+ + breakinfo->skip);
+ break;
+ case 7:
+ wpdactl |= WPDAEN1|WPDCNTEN1|WPDSRC1;
+ wpdactl |= breakinfo[breakno].dataacc
+ << WPDACC1_OFFSET;
+ bfin_write_WPDA1(breakinfo[breakno].addr);
+ bfin_write_WPDACNT1(breakinfo[breakno].count
+ + breakinfo->skip);
break;
}
}
- }
- if (correctit) {
- wpdactl &= ~WPAND;
- wpdactl |= WPPWR;
- /*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/
+
+ /* Should enable WPPWR bit first before set any other
+ * WPIACTL and WPDACTL bits */
+ if (enable_wp) {
+ bfin_write_WPIACTL(WPPWR);
+ CSYNC();
+ bfin_write_WPIACTL(wpiactl|WPPWR);
bfin_write_WPDACTL(wpdactl);
CSYNC();
- /*kgdb_show_info();*/
}
}
void kgdb_disable_hw_debug(struct pt_regs *regs)
{
/* Disable hardware debugging while we are in kgdb */
- bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1);
+ bfin_write_WPIACTL(0);
+ bfin_write_WPDACTL(0);
CSYNC();
}
-void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+#ifdef CONFIG_SMP
+void kgdb_passive_cpu_callback(void *info)
+{
+ kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+ smp_call_function(kgdb_passive_cpu_callback, NULL, 0, 0);
+}
+
+void kgdb_roundup_cpu(int cpu, unsigned long flags)
+{
+ smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0, 0);
+}
+#endif
+
+void kgdb_post_primary_code(struct pt_regs *regs, int eVector, int err_code)
{
/* Master processor is completely in the debugger */
- gdb_bf533vector = eVector;
- gdb_bf533errcode = err_code;
+ gdb_bfin_vector = eVector;
+ gdb_bfin_errcode = err_code;
}
-int kgdb_arch_handle_exception(int exceptionVector, int signo,
+int kgdb_arch_handle_exception(int vector, int signo,
int err_code, char *remcom_in_buffer,
char *remcom_out_buffer,
- struct pt_regs *linux_regs)
+ struct pt_regs *regs)
{
long addr;
long breakno;
@@ -385,44 +404,40 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
/* try to read optional parameter, pc unchanged if no parm */
ptr = &remcom_in_buffer[1];
if (kgdb_hex2long(&ptr, &addr)) {
- linux_regs->retx = addr;
+ regs->retx = addr;
}
- newPC = linux_regs->retx;
+ newPC = regs->retx;
/* clear the trace bit */
- linux_regs->syscfg &= 0xfffffffe;
+ regs->syscfg &= 0xfffffffe;
/* set the trace bit if we're stepping */
if (remcom_in_buffer[0] == 's') {
- linux_regs->syscfg |= 0x1;
- debugger_step = linux_regs->ipend;
- debugger_step >>= 6;
- for (i = 10; i > 0; i--, debugger_step >>= 1)
- if (debugger_step & 1)
+ regs->syscfg |= 0x1;
+ kgdb_single_step = regs->ipend;
+ kgdb_single_step >>= 6;
+ for (i = 10; i > 0; i--, kgdb_single_step >>= 1)
+ if (kgdb_single_step & 1)
break;
/* i indicate event priority of current stopped instruction
* user space instruction is 0, IVG15 is 1, IVTMR is 10.
- * debugger_step > 0 means in single step mode
+ * kgdb_single_step > 0 means in single step mode
*/
- debugger_step = i + 1;
- } else {
- debugger_step = 0;
+ kgdb_single_step = i + 1;
}
- wp_status = bfin_read_WPSTAT();
- CSYNC();
-
- if (exceptionVector == VEC_WATCH) {
- for (breakno = 0; breakno < 6; ++breakno) {
+ if (vector == VEC_WATCH) {
+ wp_status = bfin_read_WPSTAT();
+ for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) {
if (wp_status & (1 << breakno)) {
breakinfo->skip = 1;
break;
}
}
+ bfin_write_WPSTAT(0);
}
- kgdb_correct_hw_break();
- bfin_write_WPSTAT(0);
+ bfin_correct_hw_break();
return 0;
} /* switch */
@@ -431,5 +446,385 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
struct kgdb_arch arch_kgdb_ops = {
.gdb_bpt_instr = {0xa1},
+#ifdef CONFIG_SMP
+ .flags = KGDB_HW_BREAKPOINT|KGDB_THR_PROC_SWAP,
+#else
.flags = KGDB_HW_BREAKPOINT,
+#endif
+ .set_hw_breakpoint = bfin_set_hw_break,
+ .remove_hw_breakpoint = bfin_remove_hw_break,
+ .remove_all_hw_break = bfin_remove_all_hw_break,
+ .correct_hw_break = bfin_correct_hw_break,
};
+
+static int hex(char ch)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ return ch - 'a' + 10;
+ if ((ch >= '0') && (ch <= '9'))
+ return ch - '0';
+ if ((ch >= 'A') && (ch <= 'F'))
+ return ch - 'A' + 10;
+ return -1;
+}
+
+static int validate_memory_access_address(unsigned long addr, int size)
+{
+ int cpu = raw_smp_processor_id();
+
+ if (size < 0)
+ return EFAULT;
+ if (addr >= 0x1000 && (addr + size) <= physical_mem_end)
+ return 0;
+ if (addr >= SYSMMR_BASE)
+ return 0;
+ if (addr >= ASYNC_BANK0_BASE
+ && addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE)
+ return 0;
+ if (cpu == 0) {
+ if (addr >= L1_SCRATCH_START
+ && (addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH))
+ return 0;
+#if L1_CODE_LENGTH != 0
+ if (addr >= L1_CODE_START
+ && (addr + size <= L1_CODE_START + L1_CODE_LENGTH))
+ return 0;
+#endif
+#if L1_DATA_A_LENGTH != 0
+ if (addr >= L1_DATA_A_START
+ && (addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH))
+ return 0;
+#endif
+#if L1_DATA_B_LENGTH != 0
+ if (addr >= L1_DATA_B_START
+ && (addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH))
+ return 0;
+#endif
+#ifdef CONFIG_SMP
+ } else if (cpu == 1) {
+ if (addr >= COREB_L1_SCRATCH_START
+ && (addr + size <= COREB_L1_SCRATCH_START
+ + L1_SCRATCH_LENGTH))
+ return 0;
+# if L1_CODE_LENGTH != 0
+ if (addr >= COREB_L1_CODE_START
+ && (addr + size <= COREB_L1_CODE_START + L1_CODE_LENGTH))
+ return 0;
+# endif
+# if L1_DATA_A_LENGTH != 0
+ if (addr >= COREB_L1_DATA_A_START
+ && (addr + size <= COREB_L1_DATA_A_START + L1_DATA_A_LENGTH))
+ return 0;
+# endif
+# if L1_DATA_B_LENGTH != 0
+ if (addr >= COREB_L1_DATA_B_START
+ && (addr + size <= COREB_L1_DATA_B_START + L1_DATA_B_LENGTH))
+ return 0;
+# endif
+#endif
+ }
+
+#if L2_LENGTH != 0
+ if (addr >= L2_START
+ && addr + size <= L2_START + L2_LENGTH)
+ return 0;
+#endif
+
+ return EFAULT;
+}
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null). May return an error.
+ */
+int kgdb_mem2hex(char *mem, char *buf, int count)
+{
+ char *tmp;
+ int err = 0;
+ unsigned char *pch;
+ unsigned short mmr16;
+ unsigned long mmr32;
+ int cpu = raw_smp_processor_id();
+
+ if (validate_memory_access_address((unsigned long)mem, count))
+ return EFAULT;
+
+ /*
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory copy. Hex conversion will work against this one.
+ */
+ tmp = buf + count;
+
+ if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+ switch (count) {
+ case 2:
+ if ((unsigned int)mem % 2 == 0) {
+ mmr16 = *(unsigned short *)mem;
+ pch = (unsigned char *)&mmr16;
+ *tmp++ = *pch++;
+ *tmp++ = *pch++;
+ tmp -= 2;
+ } else
+ err = EFAULT;
+ break;
+ case 4:
+ if ((unsigned int)mem % 4 == 0) {
+ mmr32 = *(unsigned long *)mem;
+ pch = (unsigned char *)&mmr32;
+ *tmp++ = *pch++;
+ *tmp++ = *pch++;
+ *tmp++ = *pch++;
+ *tmp++ = *pch++;
+ tmp -= 4;
+ } else
+ err = EFAULT;
+ break;
+ default:
+ err = EFAULT;
+ }
+ } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+ (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+ || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+ (unsigned int)(mem + count) <=
+ COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+ ) {
+ /* access L1 instruction SRAM*/
+ if (dma_memcpy(tmp, mem, count) == NULL)
+ err = EFAULT;
+ } else
+ err = probe_kernel_read(tmp, mem, count);
+
+ if (!err) {
+ while (count > 0) {
+ buf = pack_hex_byte(buf, *tmp);
+ tmp++;
+ count--;
+ }
+
+ *buf = 0;
+ }
+
+ return err;
+}
+
+/*
+ * Copy the binary array pointed to by buf into mem. Fix $, #, and
+ * 0x7d escaped with 0x7d. Return a pointer to the character after
+ * the last byte written.
+ */
+int kgdb_ebin2mem(char *buf, char *mem, int count)
+{
+ char *tmp_old;
+ char *tmp_new;
+ unsigned short *mmr16;
+ unsigned long *mmr32;
+ int err = 0;
+ int size = 0;
+ int cpu = raw_smp_processor_id();
+
+ tmp_old = tmp_new = buf;
+
+ while (count-- > 0) {
+ if (*tmp_old == 0x7d)
+ *tmp_new = *(++tmp_old) ^ 0x20;
+ else
+ *tmp_new = *tmp_old;
+ tmp_new++;
+ tmp_old++;
+ size++;
+ }
+
+ if (validate_memory_access_address((unsigned long)mem, size))
+ return EFAULT;
+
+ if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+ switch (size) {
+ case 2:
+ if ((unsigned int)mem % 2 == 0) {
+ mmr16 = (unsigned short *)buf;
+ *(unsigned short *)mem = *mmr16;
+ } else
+ return EFAULT;
+ break;
+ case 4:
+ if ((unsigned int)mem % 4 == 0) {
+ mmr32 = (unsigned long *)buf;
+ *(unsigned long *)mem = *mmr32;
+ } else
+ return EFAULT;
+ break;
+ default:
+ return EFAULT;
+ }
+ } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+ (unsigned int)(mem + count) < L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+ || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+ (unsigned int)(mem + count) <=
+ COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+ ) {
+ /* access L1 instruction SRAM */
+ if (dma_memcpy(mem, buf, size) == NULL)
+ err = EFAULT;
+ } else
+ err = probe_kernel_write(mem, buf, size);
+
+ return err;
+}
+
+/*
+ * Convert the hex array pointed to by buf into binary to be placed in mem.
+ * Return a pointer to the character AFTER the last byte written.
+ * May return an error.
+ */
+int kgdb_hex2mem(char *buf, char *mem, int count)
+{
+ char *tmp_raw;
+ char *tmp_hex;
+ unsigned short *mmr16;
+ unsigned long *mmr32;
+ int cpu = raw_smp_processor_id();
+
+ if (validate_memory_access_address((unsigned long)mem, count))
+ return EFAULT;
+
+ /*
+ * We use the upper half of buf as an intermediate buffer for the
+ * raw memory that is converted from hex.
+ */
+ tmp_raw = buf + count * 2;
+
+ tmp_hex = tmp_raw - 1;
+ while (tmp_hex >= buf) {
+ tmp_raw--;
+ *tmp_raw = hex(*tmp_hex--);
+ *tmp_raw |= hex(*tmp_hex--) << 4;
+ }
+
+ if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/
+ switch (count) {
+ case 2:
+ if ((unsigned int)mem % 2 == 0) {
+ mmr16 = (unsigned short *)tmp_raw;
+ *(unsigned short *)mem = *mmr16;
+ } else
+ return EFAULT;
+ break;
+ case 4:
+ if ((unsigned int)mem % 4 == 0) {
+ mmr32 = (unsigned long *)tmp_raw;
+ *(unsigned long *)mem = *mmr32;
+ } else
+ return EFAULT;
+ break;
+ default:
+ return EFAULT;
+ }
+ } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START &&
+ (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH
+#ifdef CONFIG_SMP
+ || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START &&
+ (unsigned int)(mem + count) <=
+ COREB_L1_CODE_START + L1_CODE_LENGTH
+#endif
+ ) {
+ /* access L1 instruction SRAM */
+ if (dma_memcpy(mem, tmp_raw, count) == NULL)
+ return EFAULT;
+ } else
+ return probe_kernel_write(mem, tmp_raw, count);
+ return 0;
+}
+
+int kgdb_validate_break_address(unsigned long addr)
+{
+ int cpu = raw_smp_processor_id();
+
+ if (addr >= 0x1000 && (addr + BREAK_INSTR_SIZE) <= physical_mem_end)
+ return 0;
+ if (addr >= ASYNC_BANK0_BASE
+ && addr + BREAK_INSTR_SIZE <= ASYNC_BANK3_BASE + ASYNC_BANK3_BASE)
+ return 0;
+#if L1_CODE_LENGTH != 0
+ if (cpu == 0 && addr >= L1_CODE_START
+ && addr + BREAK_INSTR_SIZE <= L1_CODE_START + L1_CODE_LENGTH)
+ return 0;
+# ifdef CONFIG_SMP
+ else if (cpu == 1 && addr >= COREB_L1_CODE_START
+ && addr + BREAK_INSTR_SIZE <= COREB_L1_CODE_START + L1_CODE_LENGTH)
+ return 0;
+# endif
+#endif
+#if L2_LENGTH != 0
+ if (addr >= L2_START
+ && addr + BREAK_INSTR_SIZE <= L2_START + L2_LENGTH)
+ return 0;
+#endif
+
+ return EFAULT;
+}
+
+int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+ int err;
+ int cpu = raw_smp_processor_id();
+
+ if ((cpu == 0 && (unsigned int)addr >= L1_CODE_START
+ && (unsigned int)(addr + BREAK_INSTR_SIZE)
+ < L1_CODE_START + L1_CODE_LENGTH)
+#ifdef CONFIG_SMP
+ || (cpu == 1 && (unsigned int)addr >= COREB_L1_CODE_START
+ && (unsigned int)(addr + BREAK_INSTR_SIZE)
+ < COREB_L1_CODE_START + L1_CODE_LENGTH)
+#endif
+ ) {
+ /* access L1 instruction SRAM */
+ if (dma_memcpy(saved_instr, (void *)addr, BREAK_INSTR_SIZE)
+ == NULL)
+ return -EFAULT;
+
+ if (dma_memcpy((void *)addr, arch_kgdb_ops.gdb_bpt_instr,
+ BREAK_INSTR_SIZE) == NULL)
+ return -EFAULT;
+
+ return 0;
+ } else {
+ err = probe_kernel_read(saved_instr, (char *)addr,
+ BREAK_INSTR_SIZE);
+ if (err)
+ return err;
+
+ return probe_kernel_write((char *)addr,
+ arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
+ }
+}
+
+int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+ if ((unsigned int)addr >= L1_CODE_START &&
+ (unsigned int)(addr + BREAK_INSTR_SIZE) <
+ L1_CODE_START + L1_CODE_LENGTH) {
+ /* access L1 instruction SRAM */
+ if (dma_memcpy((void *)addr, bundle, BREAK_INSTR_SIZE) == NULL)
+ return -EFAULT;
+
+ return 0;
+ } else
+ return probe_kernel_write((char *)addr,
+ (char *)bundle, BREAK_INSTR_SIZE);
+}
+
+int kgdb_arch_init(void)
+{
+ kgdb_single_step = 0;
+
+ bfin_remove_all_hw_break();
+ return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index bf1a51d8e60..140bf00e997 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -46,7 +46,6 @@
#include <asm/dma.h>
#include <asm/fixed_code.h>
-#define MAX_SHARED_LIBS 3
#define TEXT_OFFSET 0
/*
* does not yet catch signals sent when the child dies.
@@ -161,21 +160,32 @@ static inline int is_user_addr_valid(struct task_struct *child,
struct vm_list_struct *vml;
struct sram_list_struct *sraml;
+ /* overflow */
+ if (start + len < start)
+ return -EIO;
+
for (vml = child->mm->context.vmlist; vml; vml = vml->next)
- if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
+ if (start >= vml->vma->vm_start && start + len < vml->vma->vm_end)
return 0;
for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
if (start >= (unsigned long)sraml->addr
- && start + len <= (unsigned long)sraml->addr + sraml->length)
+ && start + len < (unsigned long)sraml->addr + sraml->length)
return 0;
- if (start >= FIXED_CODE_START && start + len <= FIXED_CODE_END)
+ if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END)
return 0;
return -EIO;
}
+void ptrace_enable(struct task_struct *child)
+{
+ unsigned long tmp;
+ tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
+ put_reg(child, PT_SYSCFG, tmp);
+}
+
/*
* Called by kernel/ptrace.c when detaching..
*
@@ -192,14 +202,12 @@ void ptrace_disable(struct task_struct *child)
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret;
- int add = 0;
unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKDATA:
pr_debug("ptrace: PEEKDATA\n");
- add = MAX_SHARED_LIBS * 4; /* space between text and data */
/* fall through */
case PTRACE_PEEKTEXT: /* read word at location addr. */
{
@@ -207,40 +215,35 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int copied;
ret = -EIO;
- pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
- sizeof(data));
- if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
+ pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %ld\n", addr, sizeof(data));
+ if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
break;
pr_debug("ptrace: user address is valid\n");
-#if L1_CODE_LENGTH != 0
- if (addr + add >= L1_CODE_START
- && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
- safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
+ if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
+ && addr + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
+ safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp));
copied = sizeof(tmp);
- } else
-#endif
-#if L1_DATA_A_LENGTH != 0
- if (addr + add >= L1_DATA_A_START
- && addr + add + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
- memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+ } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
+ && addr + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
+ memcpy(&tmp, (const void *)(addr), sizeof(tmp));
copied = sizeof(tmp);
- } else
-#endif
-#if L1_DATA_B_LENGTH != 0
- if (addr + add >= L1_DATA_B_START
- && addr + add + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
- memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+ } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
+ && addr + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
+ memcpy(&tmp, (const void *)(addr), sizeof(tmp));
copied = sizeof(tmp);
- } else
-#endif
- if (addr + add >= FIXED_CODE_START
- && addr + add + sizeof(tmp) <= FIXED_CODE_END) {
- memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
+
+ } else if (addr >= FIXED_CODE_START
+ && addr + sizeof(tmp) <= FIXED_CODE_END) {
+ memcpy(&tmp, (const void *)(addr), sizeof(tmp));
copied = sizeof(tmp);
+
} else
- copied = access_process_vm(child, addr + add, &tmp,
+ copied = access_process_vm(child, addr, &tmp,
sizeof(tmp), 0);
+
pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
if (copied != sizeof(tmp))
break;
@@ -284,47 +287,43 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKEDATA:
- printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
+ pr_debug("ptrace: PTRACE_PEEKDATA\n");
/* fall through */
case PTRACE_POKETEXT: /* write the word at location addr. */
{
int copied;
ret = -EIO;
- pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
- addr, add, sizeof(data), data);
- if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
+ pr_debug("ptrace: POKETEXT at addr 0x%08lx + %ld bytes %lx\n",
+ addr, sizeof(data), data);
+ if (is_user_addr_valid(child, addr, sizeof(data)) < 0)
break;
pr_debug("ptrace: user address is valid\n");
-#if L1_CODE_LENGTH != 0
- if (addr + add >= L1_CODE_START
- && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
- safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
+ if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
+ && addr + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
+ safe_dma_memcpy ((void *)(addr), &data, sizeof(data));
copied = sizeof(data);
- } else
-#endif
-#if L1_DATA_A_LENGTH != 0
- if (addr + add >= L1_DATA_A_START
- && addr + add + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
- memcpy((void *)(addr + add), &data, sizeof(data));
+
+ } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
+ && addr + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
+ memcpy((void *)(addr), &data, sizeof(data));
copied = sizeof(data);
- } else
-#endif
-#if L1_DATA_B_LENGTH != 0
- if (addr + add >= L1_DATA_B_START
- && addr + add + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
- memcpy((void *)(addr + add), &data, sizeof(data));
+
+ } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
+ && addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
+ memcpy((void *)(addr), &data, sizeof(data));
copied = sizeof(data);
- } else
-#endif
- if (addr + add >= FIXED_CODE_START
- && addr + add + sizeof(data) <= FIXED_CODE_END) {
- memcpy((void *)(addr + add), &data, sizeof(data));
+
+ } else if (addr >= FIXED_CODE_START
+ && addr + sizeof(data) <= FIXED_CODE_END) {
+ memcpy((void *)(addr), &data, sizeof(data));
copied = sizeof(data);
+
} else
- copied = access_process_vm(child, addr + add, &data,
+ copied = access_process_vm(child, addr, &data,
sizeof(data), 1);
+
pr_debug("ptrace: copied size %d\n", copied);
if (copied != sizeof(data))
break;
@@ -351,29 +350,22 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT:
- { /* restart after signal. */
- long tmp;
+ case PTRACE_CONT: /* restart after signal. */
+ pr_debug("ptrace: syscall/cont\n");
- pr_debug("ptrace_cont\n");
-
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL)
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- else
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
- put_reg(child, PT_SYSCFG, tmp);
- pr_debug("before wake_up_process\n");
- wake_up_process(child);
- ret = 0;
+ ret = -EIO;
+ if (!valid_signal(data))
break;
- }
+ if (request == PTRACE_SYSCALL)
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ else
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ child->exit_code = data;
+ ptrace_disable(child);
+ pr_debug("ptrace: before wake_up_process\n");
+ wake_up_process(child);
+ ret = 0;
+ break;
/*
* make the child exit. Best I can do is send it a sigkill.
@@ -381,55 +373,37 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
* exit.
*/
case PTRACE_KILL:
- {
- long tmp;
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
- put_reg(child, PT_SYSCFG, tmp);
- wake_up_process(child);
+ ret = 0;
+ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
- }
-
- case PTRACE_SINGLESTEP:
- { /* set the trap flag. */
- long tmp;
-
- pr_debug("single step\n");
- ret = -EIO;
- if (!valid_signal(data))
- break;
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-
- tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
- put_reg(child, PT_SYSCFG, tmp);
+ child->exit_code = SIGKILL;
+ ptrace_disable(child);
+ wake_up_process(child);
+ break;
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ pr_debug("ptrace: single step\n");
+ ret = -EIO;
+ if (!valid_signal(data))
break;
- }
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ ptrace_enable(child);
+ child->exit_code = data;
+ wake_up_process(child);
+ ret = 0;
+ break;
case PTRACE_GETREGS:
- {
-
- /* Get all gp regs from the child. */
- ret = ptrace_getregs(child, datap);
- break;
- }
+ /* Get all gp regs from the child. */
+ ret = ptrace_getregs(child, datap);
+ break;
case PTRACE_SETREGS:
- {
- printk(KERN_NOTICE
- "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
- /* Set all gp regs in the child. */
- ret = 0;
- break;
- }
+ printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
+ /* Set all gp regs in the child. */
+ ret = 0;
+ break;
+
default:
ret = ptrace_request(child, request, addr, data);
break;
@@ -440,7 +414,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
asmlinkage void syscall_trace(void)
{
-
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
index 367e2dc0988..ae97ca407b0 100644
--- a/arch/blackfin/kernel/reboot.c
+++ b/arch/blackfin/kernel/reboot.c
@@ -10,6 +10,7 @@
#include <asm/bfin-global.h>
#include <asm/reboot.h>
#include <asm/system.h>
+#include <asm/bfrom.h>
/* A system soft reset makes external memory unusable so force
* this function into L1. We use the compiler ssync here rather
@@ -20,7 +21,7 @@
* the core reset.
*/
__attribute__((l1_text))
-void bfin_reset(void)
+static void bfin_reset(void)
{
/* Wait for completion of "system" events such as cache line
* line fills so that we avoid infinite stalls later on as
@@ -34,15 +35,15 @@ void bfin_reset(void)
bfin_write_SWRST(0x7);
/* Due to the way reset is handled in the hardware, we need
- * to delay for 7 SCLKS. The only reliable way to do this is
- * to calculate the CCLK/SCLK ratio and multiply 7. For now,
+ * to delay for 10 SCLKS. The only reliable way to do this is
+ * to calculate the CCLK/SCLK ratio and multiply 10. For now,
* we'll assume worse case which is a 1:15 ratio.
*/
asm(
"LSETUP (1f, 1f) LC0 = %0\n"
"1: nop;"
:
- : "a" (15 * 7)
+ : "a" (15 * 10)
: "LC0", "LB0", "LT0"
);
@@ -74,7 +75,14 @@ void machine_restart(char *cmd)
{
native_machine_restart(cmd);
local_irq_disable();
- bfin_reset();
+ if (ANOMALY_05000353 || ANOMALY_05000386)
+ bfin_reset();
+ else
+ /* the bootrom checks to see how it was reset and will
+ * automatically perform a software reset for us when
+ * it starts executing boot
+ */
+ asm("raise 1;");
}
__attribute__((weak))
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 7a82d10b4eb..7f35d1046cd 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -42,6 +42,7 @@ EXPORT_SYMBOL(memory_start);
EXPORT_SYMBOL(memory_end);
EXPORT_SYMBOL(physical_mem_end);
EXPORT_SYMBOL(_ramend);
+EXPORT_SYMBOL(reserved_mem_dcache_on);
#ifdef CONFIG_MTD_UCLINUX
unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
@@ -52,7 +53,8 @@ EXPORT_SYMBOL(mtd_size);
#endif
char __initdata command_line[COMMAND_LINE_SIZE];
-unsigned int __initdata *__retx;
+void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat,
+ *init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr;
/* boot memmap, for parsing "memmap=" */
#define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */
@@ -77,10 +79,10 @@ static struct change_member *change_point[2*BFIN_MEMMAP_MAX] __initdata;
static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata;
static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata;
-void __init bf53x_cache_init(void)
+void __init bfin_cache_init(void)
{
#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)
- generate_cpl_tables();
+ generate_cplb_tables();
#endif
#ifdef CONFIG_BFIN_ICACHE
@@ -100,7 +102,7 @@ void __init bf53x_cache_init(void)
#endif
}
-void __init bf53x_relocate_l1_mem(void)
+void __init bfin_relocate_l1_mem(void)
{
unsigned long l1_code_length;
unsigned long l1_data_a_length;
@@ -410,7 +412,7 @@ static __init void parse_cmdline_early(char *cmdline_p)
* [_rambase, _ramstart]: kernel image
* [memory_start, memory_end]: dynamic memory managed by kernel
* [memory_end, _ramend]: reserved memory
- * [meory_mtd_start(memory_end),
+ * [memory_mtd_start(memory_end),
* memory_mtd_start + mtd_size]: rootfs (if any)
* [_ramend - DMA_UNCACHED_REGION,
* _ramend]: uncached DMA region
@@ -782,16 +784,25 @@ void __init setup_arch(char **cmdline_p)
_bfin_swrst = bfin_read_SWRST();
- /* If we double fault, reset the system - otherwise we hang forever */
- bfin_write_SWRST(DOUBLE_FAULT);
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+ bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT);
+#endif
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET
+ bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT);
+#endif
- if (_bfin_swrst & RESET_DOUBLE)
- /*
- * don't decode the address, since you don't know if this
- * kernel's symbol map is the same as the crashing kernel
- */
- printk(KERN_INFO "Recovering from Double Fault event at %pF\n", __retx);
- else if (_bfin_swrst & RESET_WDOG)
+ if (_bfin_swrst & RESET_DOUBLE) {
+ printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n");
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* We assume the crashing kernel, and the current symbol table match */
+ printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n",
+ (int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx);
+ printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr);
+ printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr);
+#endif
+ printk(KERN_NOTICE " The instruction at %pF caused a double exception\n",
+ init_retx);
+ } else if (_bfin_swrst & RESET_WDOG)
printk(KERN_INFO "Recovering from Watchdog event\n");
else if (_bfin_swrst & RESET_SOFTWARE)
printk(KERN_NOTICE "Reset caused by Software reset\n");
@@ -803,17 +814,24 @@ void __init setup_arch(char **cmdline_p)
printk(KERN_INFO "Compiled for ADSP-%s Rev none\n", CPU);
else
printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
- if (bfin_revid() != bfin_compiled_revid()) {
- if (bfin_compiled_revid() == -1)
- printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
- bfin_revid());
- else if (bfin_compiled_revid() != 0xffff)
- printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
- bfin_compiled_revid(), bfin_revid());
+
+ if (unlikely(CPUID != bfin_cpuid()))
+ printk(KERN_ERR "ERROR: Not running on ADSP-%s: unknown CPUID 0x%04x Rev 0.%d\n",
+ CPU, bfin_cpuid(), bfin_revid());
+ else {
+ if (bfin_revid() != bfin_compiled_revid()) {
+ if (bfin_compiled_revid() == -1)
+ printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n",
+ bfin_revid());
+ else if (bfin_compiled_revid() != 0xffff)
+ printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
+ bfin_compiled_revid(), bfin_revid());
+ }
+ if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX)
+ printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
+ CPU, bfin_revid());
}
- if (bfin_revid() < SUPPORTED_REVID)
- printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
- CPU, bfin_revid());
+
printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n",
@@ -850,7 +868,7 @@ void __init setup_arch(char **cmdline_p)
!= SAFE_USER_INSTRUCTION - FIXED_CODE_START);
init_exception_vectors();
- bf53x_cache_init();
+ bfin_cache_init();
}
static int __init topology_init(void)
@@ -986,13 +1004,18 @@ static int show_cpuinfo(struct seq_file *m, void *v)
}
seq_printf(m, "processor\t: %d\n"
- "vendor_id\t: %s\n"
- "cpu family\t: 0x%x\n"
- "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
+ "vendor_id\t: %s\n",
+ *(unsigned int *)v,
+ vendor);
+
+ if (CPUID == bfin_cpuid())
+ seq_printf(m, "cpu family\t: 0x%04x\n", CPUID);
+ else
+ seq_printf(m, "cpu family\t: Compiled for:0x%04x, running on:0x%04x\n",
+ CPUID, bfin_cpuid());
+
+ seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
"stepping\t: %d\n",
- 0,
- vendor,
- (bfin_read_CHIPID() & CHIPID_FAMILY),
cpu, cclk/1000000, sclk/1000000,
#ifdef CONFIG_MPU
"mpu on",
@@ -1038,7 +1061,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if ((bfin_read_DMEM_CONTROL() & (ENDCPLB | DMC_ENABLE)) != (ENDCPLB | DMC_ENABLE))
dcache_size = 0;
- if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) == (IMC | ENICPLB))
+ if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) != (IMC | ENICPLB))
icache_size = 0;
seq_printf(m, "cache size\t: %d KB(L1 icache) "
@@ -1127,12 +1150,18 @@ static int show_cpuinfo(struct seq_file *m, void *v)
static void *c_start(struct seq_file *m, loff_t *pos)
{
- return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
+ if (*pos == 0)
+ *pos = first_cpu(cpu_online_map);
+ if (*pos >= num_online_cpus())
+ return NULL;
+
+ return pos;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
- ++*pos;
+ *pos = next_cpu(*pos, cpu_online_map);
+
return c_start(m, pos);
}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 9a9d5083acf..1aa2c788e22 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -34,20 +34,19 @@
#include <linux/fs.h>
#include <asm/traps.h>
#include <asm/cacheflush.h>
+#include <asm/cplb.h>
#include <asm/blackfin.h>
#include <asm/irq_handler.h>
#include <linux/irq.h>
#include <asm/trace.h>
#include <asm/fixed_code.h>
-#include <asm/dma.h>
#ifdef CONFIG_KGDB
-# include <linux/debugger.h>
# include <linux/kgdb.h>
# define CHK_DEBUGGER_TRAP() \
do { \
- CHK_DEBUGGER(trapnr, sig, info.si_code, fp, ); \
+ kgdb_handle_exception(trapnr, sig, info.si_code, fp); \
} while (0)
# define CHK_DEBUGGER_TRAP_MAYBE() \
do { \
@@ -59,6 +58,15 @@
# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
#endif
+
+#ifdef CONFIG_VERBOSE_DEBUG
+#define verbose_printk(fmt, arg...) \
+ printk(fmt, ##arg)
+#else
+#define verbose_printk(fmt, arg...) \
+ ({ if (0) printk(fmt, ##arg); 0; })
+#endif
+
/* Initiate the event table handler */
void __init trap_init(void)
{
@@ -67,10 +75,19 @@ void __init trap_init(void)
CSYNC();
}
-unsigned long saved_icplb_fault_addr, saved_dcplb_fault_addr;
+/*
+ * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR
+ * values across the transition from exception to IRQ5.
+ * We put these in L1, so they are going to be in a valid
+ * location during exception context
+ */
+__attribute__((l1_data))
+unsigned long saved_retx, saved_seqstat,
+ saved_icplb_fault_addr, saved_dcplb_fault_addr;
static void decode_address(char *buf, unsigned long address)
{
+#ifdef CONFIG_DEBUG_VERBOSE
struct vm_list_struct *vml;
struct task_struct *p;
struct mm_struct *mm;
@@ -178,16 +195,39 @@ static void decode_address(char *buf, unsigned long address)
done:
write_unlock_irqrestore(&tasklist_lock, flags);
+#else
+ sprintf(buf, " ");
+#endif
}
asmlinkage void double_fault_c(struct pt_regs *fp)
{
console_verbose();
oops_in_progress = 1;
+#ifdef CONFIG_DEBUG_VERBOSE
printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
- dump_bfin_process(fp);
- dump_bfin_mem(fp);
- show_regs(fp);
+#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
+ if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) {
+ char buf[150];
+ decode_address(buf, saved_retx);
+ printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n",
+ (int)saved_seqstat & SEQSTAT_EXCAUSE, buf);
+ decode_address(buf, saved_dcplb_fault_addr);
+ printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf);
+ decode_address(buf, saved_icplb_fault_addr);
+ printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf);
+
+ decode_address(buf, fp->retx);
+ printk(KERN_NOTICE "The instruction at %s caused a double exception\n",
+ buf);
+ } else
+#endif
+ {
+ dump_bfin_process(fp);
+ dump_bfin_mem(fp);
+ show_regs(fp);
+ }
+#endif
panic("Double Fault - unrecoverable event\n");
}
@@ -259,34 +299,42 @@ asmlinkage void trap_c(struct pt_regs *fp)
return;
else
break;
+ /* 0x03 - User Defined, userspace stack overflow */
+ case VEC_EXCPT03:
+ info.si_code = SEGV_STACKFLOW;
+ sig = SIGSEGV;
+ verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
+ break;
+ /* 0x02 - KGDB initial connection and break signal trap */
+ case VEC_EXCPT02:
#ifdef CONFIG_KGDB
- case VEC_EXCPT02 : /* gdb connection */
info.si_code = TRAP_ILLTRAP;
sig = SIGTRAP;
CHK_DEBUGGER_TRAP();
return;
-#else
- /* 0x02 - User Defined, Caught by default */
#endif
- /* 0x03 - User Defined, userspace stack overflow */
- case VEC_EXCPT03:
- info.si_code = SEGV_STACKFLOW;
- sig = SIGSEGV;
- printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ /* 0x04 - User Defined */
+ /* 0x05 - User Defined */
+ /* 0x06 - User Defined */
+ /* 0x07 - User Defined */
+ /* 0x08 - User Defined */
+ /* 0x09 - User Defined */
+ /* 0x0A - User Defined */
+ /* 0x0B - User Defined */
+ /* 0x0C - User Defined */
+ /* 0x0D - User Defined */
+ /* 0x0E - User Defined */
+ /* 0x0F - User Defined */
+ /* If we got here, it is most likely that someone was trying to use a
+ * custom exception handler, and it is not actually installed properly
+ */
+ case VEC_EXCPT04 ... VEC_EXCPT15:
+ info.si_code = ILL_ILLPARAOP;
+ sig = SIGILL;
+ verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
- /* 0x04 - User Defined, Caught by default */
- /* 0x05 - User Defined, Caught by default */
- /* 0x06 - User Defined, Caught by default */
- /* 0x07 - User Defined, Caught by default */
- /* 0x08 - User Defined, Caught by default */
- /* 0x09 - User Defined, Caught by default */
- /* 0x0A - User Defined, Caught by default */
- /* 0x0B - User Defined, Caught by default */
- /* 0x0C - User Defined, Caught by default */
- /* 0x0D - User Defined, Caught by default */
- /* 0x0E - User Defined, Caught by default */
- /* 0x0F - User Defined, Caught by default */
/* 0x10 HW Single step, handled here */
case VEC_STEP:
info.si_code = TRAP_STEP;
@@ -301,8 +349,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
case VEC_OVFLOW:
info.si_code = TRAP_TRACEFLOW;
sig = SIGTRAP;
- printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x12 - Reserved, Caught by default */
/* 0x13 - Reserved, Caught by default */
@@ -323,44 +371,43 @@ asmlinkage void trap_c(struct pt_regs *fp)
case VEC_UNDEF_I:
info.si_code = ILL_ILLOPC;
sig = SIGILL;
- printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x22 - Illegal Instruction Combination, handled here */
case VEC_ILGAL_I:
info.si_code = ILL_ILLPARAOP;
sig = SIGILL;
- printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x23 - Data CPLB protection violation, handled here */
case VEC_CPLB_VL:
info.si_code = ILL_CPLB_VI;
sig = SIGBUS;
- printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x24 - Data access misaligned, handled here */
case VEC_MISALI_D:
info.si_code = BUS_ADRALN;
sig = SIGBUS;
- printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x25 - Unrecoverable Event, handled here */
case VEC_UNCOV:
info.si_code = ILL_ILLEXCPT;
sig = SIGILL;
- printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
error case is handled here */
case VEC_CPLB_M:
info.si_code = BUS_ADRALN;
sig = SIGBUS;
- printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
break;
/* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
case VEC_CPLB_MHIT:
@@ -368,11 +415,11 @@ asmlinkage void trap_c(struct pt_regs *fp)
sig = SIGSEGV;
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
if (saved_dcplb_fault_addr < FIXED_CODE_START)
- printk(KERN_NOTICE "NULL pointer access\n");
+ verbose_printk(KERN_NOTICE "NULL pointer access\n");
else
#endif
- printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x28 - Emulation Watchpoint, handled here */
case VEC_WATCH:
@@ -390,8 +437,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */
info.si_code = BUS_OPFETCH;
sig = SIGBUS;
- printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
#else
/* 0x29 - Reserved, Caught by default */
@@ -400,22 +447,21 @@ asmlinkage void trap_c(struct pt_regs *fp)
case VEC_MISALI_I:
info.si_code = BUS_ADRALN;
sig = SIGBUS;
- printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x2B - Instruction CPLB protection violation, handled here */
case VEC_CPLB_I_VL:
info.si_code = ILL_CPLB_VI;
sig = SIGBUS;
- printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
case VEC_CPLB_I_M:
info.si_code = ILL_CPLB_MISS;
sig = SIGBUS;
- printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
break;
/* 0x2D - Instruction CPLB Multiple Hits, handled here */
case VEC_CPLB_I_MHIT:
@@ -423,18 +469,18 @@ asmlinkage void trap_c(struct pt_regs *fp)
sig = SIGSEGV;
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
if (saved_icplb_fault_addr < FIXED_CODE_START)
- printk(KERN_NOTICE "Jump to NULL address\n");
+ verbose_printk(KERN_NOTICE "Jump to NULL address\n");
else
#endif
- printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x2E - Illegal use of Supervisor Resource, handled here */
case VEC_ILL_RES:
info.si_code = ILL_PRVOPC;
sig = SIGILL;
- printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
- CHK_DEBUGGER_TRAP();
+ verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
/* 0x2F - Reserved, Caught by default */
/* 0x30 - Reserved, Caught by default */
@@ -461,17 +507,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
info.si_code = BUS_ADRALN;
sig = SIGBUS;
- printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+ verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
break;
/* External Memory Addressing Error */
case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
info.si_code = BUS_ADRERR;
sig = SIGBUS;
- printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+ verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
break;
/* Performance Monitor Overflow */
case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
- printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+ verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
break;
/* RAISE 5 instruction */
case (SEQSTAT_HWERRCAUSE_RAISE_5):
@@ -481,21 +527,25 @@ asmlinkage void trap_c(struct pt_regs *fp)
printk(KERN_NOTICE HWC_default(KERN_NOTICE));
break;
}
- CHK_DEBUGGER_TRAP();
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
+ /*
+ * We should be handling all known exception types above,
+ * if we get here we hit a reserved one, so panic
+ */
default:
- info.si_code = TRAP_ILLTRAP;
- sig = SIGTRAP;
- printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
+ oops_in_progress = 1;
+ info.si_code = ILL_ILLPARAOP;
+ sig = SIGILL;
+ verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
(fp->seqstat & SEQSTAT_EXCAUSE));
- CHK_DEBUGGER_TRAP();
+ CHK_DEBUGGER_TRAP_MAYBE();
break;
}
BUG_ON(sig == 0);
if (sig != SIGTRAP) {
- unsigned long *stack;
dump_bfin_process(fp);
dump_bfin_mem(fp);
show_regs(fp);
@@ -503,7 +553,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
/* Print out the trace buffer if it makes sense */
#ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M)
- printk(KERN_NOTICE "No trace since you do not have "
+ verbose_printk(KERN_NOTICE "No trace since you do not have "
"CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n"
KERN_NOTICE "\n");
else
@@ -512,20 +562,22 @@ asmlinkage void trap_c(struct pt_regs *fp)
if (oops_in_progress) {
/* Dump the current kernel stack */
- printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
+ verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n");
show_stack(current, NULL);
-
print_modules();
#ifndef CONFIG_ACCESS_CHECK
- printk(KERN_EMERG "Please turn on "
+ verbose_printk(KERN_EMERG "Please turn on "
"CONFIG_ACCESS_CHECK\n");
#endif
panic("Kernel exception");
} else {
+#ifdef CONFIG_VERBOSE_DEBUG
+ unsigned long *stack;
/* Dump the user space stack */
stack = (unsigned long *)rdusp();
- printk(KERN_NOTICE "Userspace Stack\n");
+ verbose_printk(KERN_NOTICE "Userspace Stack\n");
show_stack(NULL, stack);
+#endif
}
}
@@ -546,7 +598,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
* Similar to get_user, do some address checking, then dereference
* Return true on sucess, false on bad address
*/
-bool get_instruction(unsigned short *val, unsigned short *address)
+static bool get_instruction(unsigned short *val, unsigned short *address)
{
unsigned long addr;
@@ -592,7 +644,7 @@ bool get_instruction(unsigned short *val, unsigned short *address)
#if L1_CODE_LENGTH != 0
if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) {
- dma_memcpy(val, address, 2);
+ isram_memcpy(val, address, 2);
return true;
}
#endif
@@ -607,45 +659,48 @@ bool get_instruction(unsigned short *val, unsigned short *address)
* These are the normal instructions which cause change of flow, which
* would be at the source of the trace buffer
*/
-void decode_instruction(unsigned short *address)
+#ifdef CONFIG_DEBUG_VERBOSE
+static void decode_instruction(unsigned short *address)
{
unsigned short opcode;
if (get_instruction(&opcode, address)) {
if (opcode == 0x0010)
- printk("RTS");
+ verbose_printk("RTS");
else if (opcode == 0x0011)
- printk("RTI");
+ verbose_printk("RTI");
else if (opcode == 0x0012)
- printk("RTX");
+ verbose_printk("RTX");
else if (opcode >= 0x0050 && opcode <= 0x0057)
- printk("JUMP (P%i)", opcode & 7);
+ verbose_printk("JUMP (P%i)", opcode & 7);
else if (opcode >= 0x0060 && opcode <= 0x0067)
- printk("CALL (P%i)", opcode & 7);
+ verbose_printk("CALL (P%i)", opcode & 7);
else if (opcode >= 0x0070 && opcode <= 0x0077)
- printk("CALL (PC+P%i)", opcode & 7);
+ verbose_printk("CALL (PC+P%i)", opcode & 7);
else if (opcode >= 0x0080 && opcode <= 0x0087)
- printk("JUMP (PC+P%i)", opcode & 7);
+ verbose_printk("JUMP (PC+P%i)", opcode & 7);
else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF))
- printk("IF !CC JUMP");
+ verbose_printk("IF !CC JUMP");
else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff))
- printk("IF CC JUMP");
+ verbose_printk("IF CC JUMP");
else if (opcode >= 0x2000 && opcode <= 0x2fff)
- printk("JUMP.S");
+ verbose_printk("JUMP.S");
else if (opcode >= 0xe080 && opcode <= 0xe0ff)
- printk("LSETUP");
+ verbose_printk("LSETUP");
else if (opcode >= 0xe200 && opcode <= 0xe2ff)
- printk("JUMP.L");
+ verbose_printk("JUMP.L");
else if (opcode >= 0xe300 && opcode <= 0xe3ff)
- printk("CALL pcrel");
+ verbose_printk("CALL pcrel");
else
- printk("0x%04x", opcode);
+ verbose_printk("0x%04x", opcode);
}
}
+#endif
void dump_bfin_trace_buffer(void)
{
+#ifdef CONFIG_DEBUG_VERBOSE
#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
int tflags, i = 0;
char buf[150];
@@ -701,6 +756,7 @@ void dump_bfin_trace_buffer(void)
trace_buffer_restore(tflags);
#endif
+#endif
}
EXPORT_SYMBOL(dump_bfin_trace_buffer);
@@ -708,7 +764,7 @@ EXPORT_SYMBOL(dump_bfin_trace_buffer);
* Checks to see if the address pointed to is either a
* 16-bit CALL instruction, or a 32-bit CALL instruction
*/
-bool is_bfin_call(unsigned short *addr)
+static bool is_bfin_call(unsigned short *addr)
{
unsigned short opcode = 0, *ins_addr;
ins_addr = (unsigned short *)addr;
@@ -730,8 +786,10 @@ bool is_bfin_call(unsigned short *addr)
return false;
}
+
void show_stack(struct task_struct *task, unsigned long *stack)
{
+#ifdef CONFIG_PRINTK
unsigned int *addr, *endstack, *fp = 0, *frame;
unsigned short *ins_addr;
char buf[150];
@@ -756,8 +814,10 @@ void show_stack(struct task_struct *task, unsigned long *stack)
} else
endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack);
+ printk(KERN_NOTICE "Stack info:\n");
decode_address(buf, (unsigned int)stack);
- printk(KERN_NOTICE "Stack info:\n" KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
+ printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf);
+
addr = (unsigned int *)((unsigned int)stack & ~0x3F);
/* First thing is to look for a frame pointer */
@@ -848,7 +908,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
if (!j)
printk("\n");
}
-
+#endif
}
void dump_stack(void)
@@ -866,38 +926,39 @@ EXPORT_SYMBOL(dump_stack);
void dump_bfin_process(struct pt_regs *fp)
{
+#ifdef CONFIG_DEBUG_VERBOSE
/* We should be able to look at fp->ipend, but we don't push it on the
* stack all the time, so do this until we fix that */
unsigned int context = bfin_read_IPEND();
if (oops_in_progress)
- printk(KERN_EMERG "Kernel OOPS in progress\n");
+ verbose_printk(KERN_EMERG "Kernel OOPS in progress\n");
if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
- printk(KERN_NOTICE "HW Error context\n");
+ verbose_printk(KERN_NOTICE "HW Error context\n");
else if (context & 0x0020)
- printk(KERN_NOTICE "Deferred Exception context\n");
+ verbose_printk(KERN_NOTICE "Deferred Exception context\n");
else if (context & 0x3FC0)
- printk(KERN_NOTICE "Interrupt context\n");
+ verbose_printk(KERN_NOTICE "Interrupt context\n");
else if (context & 0x4000)
- printk(KERN_NOTICE "Deferred Interrupt context\n");
+ verbose_printk(KERN_NOTICE "Deferred Interrupt context\n");
else if (context & 0x8000)
- printk(KERN_NOTICE "Kernel process context\n");
+ verbose_printk(KERN_NOTICE "Kernel process context\n");
/* Because we are crashing, and pointers could be bad, we check things
* pretty closely before we use them
*/
if ((unsigned long)current >= FIXED_CODE_START &&
!((unsigned long)current & 0x3) && current->pid) {
- printk(KERN_NOTICE "CURRENT PROCESS:\n");
+ verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n");
if (current->comm >= (char *)FIXED_CODE_START)
- printk(KERN_NOTICE "COMM=%s PID=%d\n",
+ verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n",
current->comm, current->pid);
else
- printk(KERN_NOTICE "COMM= invalid\n");
+ verbose_printk(KERN_NOTICE "COMM= invalid\n");
if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
- printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
+ verbose_printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
KERN_NOTICE " BSS = 0x%p-0x%p USER-STACK = 0x%p\n"
KERN_NOTICE "\n",
(void *)current->mm->start_code,
@@ -908,38 +969,40 @@ void dump_bfin_process(struct pt_regs *fp)
(void *)current->mm->brk,
(void *)current->mm->start_stack);
else
- printk(KERN_NOTICE "invalid mm\n");
+ verbose_printk(KERN_NOTICE "invalid mm\n");
} else
- printk(KERN_NOTICE "\n" KERN_NOTICE
+ verbose_printk(KERN_NOTICE "\n" KERN_NOTICE
"No Valid process in current context\n");
+#endif
}
void dump_bfin_mem(struct pt_regs *fp)
{
+#ifdef CONFIG_DEBUG_VERBOSE
unsigned short *addr, *erraddr, val = 0, err = 0;
char sti = 0, buf[6];
erraddr = (void *)fp->pc;
- printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
+ verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
addr++) {
if (!((unsigned long)addr & 0xF))
- printk("\n" KERN_NOTICE "0x%p: ", addr);
+ verbose_printk("\n" KERN_NOTICE "0x%p: ", addr);
- if (get_instruction(&val, addr)) {
+ if (!get_instruction(&val, addr)) {
val = 0;
sprintf(buf, "????");
} else
sprintf(buf, "%04x", val);
if (addr == erraddr) {
- printk("[%s]", buf);
+ verbose_printk("[%s]", buf);
err = val;
} else
- printk(" %s ", buf);
+ verbose_printk(" %s ", buf);
/* Do any previous instructions turn on interrupts? */
if (addr <= erraddr && /* in the past */
@@ -948,14 +1011,14 @@ void dump_bfin_mem(struct pt_regs *fp)
sti = 1;
}
- printk("\n");
+ verbose_printk("\n");
/* Hardware error interrupts can be deferred */
if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
oops_in_progress)){
- printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
+ verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
#ifndef CONFIG_DEBUG_HWERR
- printk(KERN_NOTICE "The remaining message may be meaningless\n"
+ verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n"
KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
" better idea where it came from\n");
#else
@@ -969,34 +1032,47 @@ void dump_bfin_mem(struct pt_regs *fp)
/* And the last RETI points to the current userspace context */
if ((fp + 1)->pc >= current->mm->start_code &&
(fp + 1)->pc <= current->mm->end_code) {
- printk(KERN_NOTICE "It might be better to look around here : \n");
- printk(KERN_NOTICE "-------------------------------------------\n");
+ verbose_printk(KERN_NOTICE "It might be better to look around here : \n");
+ verbose_printk(KERN_NOTICE "-------------------------------------------\n");
show_regs(fp + 1);
- printk(KERN_NOTICE "-------------------------------------------\n");
+ verbose_printk(KERN_NOTICE "-------------------------------------------\n");
}
}
#endif
}
+#endif
}
void show_regs(struct pt_regs *fp)
{
+#ifdef CONFIG_DEBUG_VERBOSE
char buf [150];
struct irqaction *action;
unsigned int i;
unsigned long flags;
- printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
- printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n",
+ verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
+ verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n",
(long)fp->seqstat, fp->ipend, fp->syscfg);
- printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n",
- (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
- printk(KERN_NOTICE " EXCAUSE : 0x%lx\n",
+ if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) {
+ verbose_printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n",
+ (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
+#ifdef EBIU_ERRMST
+ /* If the error was from the EBIU, print it out */
+ if (bfin_read_EBIU_ERRMST() & CORE_ERROR) {
+ verbose_printk(KERN_NOTICE " EBIU Error Reason : 0x%04x\n",
+ bfin_read_EBIU_ERRMST());
+ verbose_printk(KERN_NOTICE " EBIU Error Address : 0x%08x\n",
+ bfin_read_EBIU_ERRADD());
+ }
+#endif
+ }
+ verbose_printk(KERN_NOTICE " EXCAUSE : 0x%lx\n",
fp->seqstat & SEQSTAT_EXCAUSE);
for (i = 6; i <= 15 ; i++) {
if (fp->ipend & (1 << i)) {
decode_address(buf, bfin_read32(EVT0 + 4*i));
- printk(KERN_NOTICE " physical IVG%i asserted : %s\n", i, buf);
+ verbose_printk(KERN_NOTICE " physical IVG%i asserted : %s\n", i, buf);
}
}
@@ -1009,64 +1085,65 @@ void show_regs(struct pt_regs *fp)
goto unlock;
decode_address(buf, (unsigned int)action->handler);
- printk(KERN_NOTICE " logical irq %3d mapped : %s", i, buf);
+ verbose_printk(KERN_NOTICE " logical irq %3d mapped : %s", i, buf);
for (action = action->next; action; action = action->next) {
decode_address(buf, (unsigned int)action->handler);
- printk(", %s", buf);
+ verbose_printk(", %s", buf);
}
- printk("\n");
+ verbose_printk("\n");
unlock:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
}
}
decode_address(buf, fp->rete);
- printk(KERN_NOTICE " RETE: %s\n", buf);
+ verbose_printk(KERN_NOTICE " RETE: %s\n", buf);
decode_address(buf, fp->retn);
- printk(KERN_NOTICE " RETN: %s\n", buf);
+ verbose_printk(KERN_NOTICE " RETN: %s\n", buf);
decode_address(buf, fp->retx);
- printk(KERN_NOTICE " RETX: %s\n", buf);
+ verbose_printk(KERN_NOTICE " RETX: %s\n", buf);
decode_address(buf, fp->rets);
- printk(KERN_NOTICE " RETS: %s\n", buf);
+ verbose_printk(KERN_NOTICE " RETS: %s\n", buf);
decode_address(buf, fp->pc);
- printk(KERN_NOTICE " PC : %s\n", buf);
+ verbose_printk(KERN_NOTICE " PC : %s\n", buf);
if (((long)fp->seqstat & SEQSTAT_EXCAUSE) &&
(((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
decode_address(buf, saved_dcplb_fault_addr);
- printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
+ verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
decode_address(buf, saved_icplb_fault_addr);
- printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
+ verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf);
}
- printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
- printk(KERN_NOTICE " R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
+ verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n");
+ verbose_printk(KERN_NOTICE " R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n",
fp->r0, fp->r1, fp->r2, fp->r3);
- printk(KERN_NOTICE " R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
+ verbose_printk(KERN_NOTICE " R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n",
fp->r4, fp->r5, fp->r6, fp->r7);
- printk(KERN_NOTICE " P0 : %08lx P1 : %08lx P2 : %08lx P3 : %08lx\n",
+ verbose_printk(KERN_NOTICE " P0 : %08lx P1 : %08lx P2 : %08lx P3 : %08lx\n",
fp->p0, fp->p1, fp->p2, fp->p3);
- printk(KERN_NOTICE " P4 : %08lx P5 : %08lx FP : %08lx SP : %08lx\n",
+ verbose_printk(KERN_NOTICE " P4 : %08lx P5 : %08lx FP : %08lx SP : %08lx\n",
fp->p4, fp->p5, fp->fp, (long)fp);
- printk(KERN_NOTICE " LB0: %08lx LT0: %08lx LC0: %08lx\n",
+ verbose_printk(KERN_NOTICE " LB0: %08lx LT0: %08lx LC0: %08lx\n",
fp->lb0, fp->lt0, fp->lc0);
- printk(KERN_NOTICE " LB1: %08lx LT1: %08lx LC1: %08lx\n",
+ verbose_printk(KERN_NOTICE " LB1: %08lx LT1: %08lx LC1: %08lx\n",
fp->lb1, fp->lt1, fp->lc1);
- printk(KERN_NOTICE " B0 : %08lx L0 : %08lx M0 : %08lx I0 : %08lx\n",
+ verbose_printk(KERN_NOTICE " B0 : %08lx L0 : %08lx M0 : %08lx I0 : %08lx\n",
fp->b0, fp->l0, fp->m0, fp->i0);
- printk(KERN_NOTICE " B1 : %08lx L1 : %08lx M1 : %08lx I1 : %08lx\n",
+ verbose_printk(KERN_NOTICE " B1 : %08lx L1 : %08lx M1 : %08lx I1 : %08lx\n",
fp->b1, fp->l1, fp->m1, fp->i1);
- printk(KERN_NOTICE " B2 : %08lx L2 : %08lx M2 : %08lx I2 : %08lx\n",
+ verbose_printk(KERN_NOTICE " B2 : %08lx L2 : %08lx M2 : %08lx I2 : %08lx\n",
fp->b2, fp->l2, fp->m2, fp->i2);
- printk(KERN_NOTICE " B3 : %08lx L3 : %08lx M3 : %08lx I3 : %08lx\n",
+ verbose_printk(KERN_NOTICE " B3 : %08lx L3 : %08lx M3 : %08lx I3 : %08lx\n",
fp->b3, fp->l3, fp->m3, fp->i3);
- printk(KERN_NOTICE "A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n",
+ verbose_printk(KERN_NOTICE "A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n",
fp->a0w, fp->a0x, fp->a1w, fp->a1x);
- printk(KERN_NOTICE "USP : %08lx ASTAT: %08lx\n",
+ verbose_printk(KERN_NOTICE "USP : %08lx ASTAT: %08lx\n",
rdusp(), fp->astat);
- printk(KERN_NOTICE "\n");
+ verbose_printk(KERN_NOTICE "\n");
+#endif
}
#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
diff --git a/arch/blackfin/mach-bf527/boards/Kconfig b/arch/blackfin/mach-bf527/boards/Kconfig
index 8bf9e58f014..df224d04e16 100644
--- a/arch/blackfin/mach-bf527/boards/Kconfig
+++ b/arch/blackfin/mach-bf527/boards/Kconfig
@@ -14,4 +14,9 @@ config BFIN527_BLUETECHNIX_CM
help
CM-BF527 support for EVAL- and DEV-Board.
+config BFIN526_EZBRD
+ bool "BF526-EZBRD"
+ help
+ BF526-EZBRD/EZKIT Lite board support.
+
endchoice
diff --git a/arch/blackfin/mach-bf527/boards/Makefile b/arch/blackfin/mach-bf527/boards/Makefile
index 7ba7d256bbb..eb6ed3362f9 100644
--- a/arch/blackfin/mach-bf527/boards/Makefile
+++ b/arch/blackfin/mach-bf527/boards/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_BFIN527_EZKIT) += ezkit.o
obj-$(CONFIG_BFIN527_BLUETECHNIX_CM) += cm_bf527.o
+obj-$(CONFIG_BFIN526_EZBRD) += ezbrd.o
diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c
index d22bc777371..9ea440bbb13 100644
--- a/arch/blackfin/mach-bf527/boards/cm_bf527.c
+++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c
@@ -43,10 +43,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb/sl811.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
#include <linux/usb/musb.h>
-#endif
-#include <asm/cplb.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>
@@ -130,6 +127,16 @@ static struct resource musb_resources[] = {
},
};
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 0,
+ .dyn_fifo = 0,
+ .soft_con = 1,
+ .dma = 1,
+ .num_eps = 7,
+ .dma_channels = 7,
+ .gpio_vrsel = GPIO_PF11,
+};
+
static struct musb_hdrc_platform_data musb_plat = {
#if defined(CONFIG_USB_MUSB_OTG)
.mode = MUSB_OTG,
@@ -138,7 +145,7 @@ static struct musb_hdrc_platform_data musb_plat = {
#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
.mode = MUSB_PERIPHERAL,
#endif
- .multipoint = 0,
+ .config = &musb_config,
};
static u64 musb_dmamask = ~(u32)0;
@@ -201,7 +208,7 @@ static struct mtd_partition partition_info[] = {
{
.name = "linux kernel(nand)",
.offset = 0,
- .size = 4 * SIZE_1M,
+ .size = 4 * 1024 * 1024,
},
{
.name = "file system(nand)",
diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c
new file mode 100644
index 00000000000..36c87b6fbde
--- /dev/null
+++ b/arch/blackfin/mach-bf527/boards/ezbrd.c
@@ -0,0 +1,734 @@
+/*
+ * File: arch/blackfin/mach-bf527/boards/ezbrd.c
+ * Based on: arch/blackfin/mach-bf537/boards/stamp.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/musb.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+#include <asm/dpmc.h>
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "BF526-EZBRD";
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct resource musb_resources[] = {
+ [0] = {
+ .start = 0xffc03800,
+ .end = 0xffc03cff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = { /* general IRQ */
+ .start = IRQ_USB_INT0,
+ .end = IRQ_USB_INT0,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+ [2] = { /* DMA IRQ */
+ .start = IRQ_USB_DMA,
+ .end = IRQ_USB_DMA,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 0,
+ .dyn_fifo = 0,
+ .soft_con = 1,
+ .dma = 1,
+ .num_eps = 7,
+ .dma_channels = 7,
+ .gpio_vrsel = GPIO_PG13,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+ .mode = MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+ .mode = MUSB_PERIPHERAL,
+#endif
+ .config = &musb_config,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+ .name = "musb_hdrc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &musb_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &musb_plat,
+ },
+ .num_resources = ARRAY_SIZE(musb_resources),
+ .resource = musb_resources,
+};
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+static struct mtd_partition ezbrd_partitions[] = {
+ {
+ .name = "bootloader(nor)",
+ .size = 0x40000,
+ .offset = 0,
+ }, {
+ .name = "linux kernel(nor)",
+ .size = 0x1C0000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "file system(nor)",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+static struct physmap_flash_data ezbrd_flash_data = {
+ .width = 2,
+ .parts = ezbrd_partitions,
+ .nr_parts = ARRAY_SIZE(ezbrd_partitions),
+};
+
+static struct resource ezbrd_flash_resource = {
+ .start = 0x20000000,
+ .end = 0x203fffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ezbrd_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &ezbrd_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &ezbrd_flash_resource,
+};
+#endif
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+static struct mtd_partition partition_info[] = {
+ {
+ .name = "linux kernel(nand)",
+ .offset = 0,
+ .size = 4 * 1024 * 1024,
+ },
+ {
+ .name = "file system(nand)",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct bf5xx_nand_platform bf5xx_nand_platform = {
+ .page_size = NFC_PG_SIZE_256,
+ .data_width = NFC_NWIDTH_8,
+ .partitions = partition_info,
+ .nr_partitions = ARRAY_SIZE(partition_info),
+ .rd_dly = 3,
+ .wr_dly = 3,
+};
+
+static struct resource bf5xx_nand_resources[] = {
+ {
+ .start = NFC_CTL,
+ .end = NFC_DATA_RD + 2,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = CH_NFC,
+ .end = CH_NFC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bf5xx_nand_device = {
+ .name = "bf5xx-nand",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bf5xx_nand_resources),
+ .resource = bf5xx_nand_resources,
+ .dev = {
+ .platform_data = &bf5xx_nand_platform,
+ },
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+ .name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_MTD_M25P80) \
+ || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader(spi)",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ }, {
+ .name = "linux kernel(spi)",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p16",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+ || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+ .enable_dma = 1,
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+ .ctl_reg = 0x4, /* send zero */
+ .enable_dma = 0,
+ .bits_per_word = 8,
+ .cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+ .model = 7877,
+ .vref_delay_usecs = 50, /* internal, no capacitor */
+ .x_plate_ohms = 419,
+ .y_plate_ohms = 486,
+ .pressure_max = 1000,
+ .pressure_min = 0,
+ .stopacq_polarity = 1,
+ .first_conversion_delay = 3,
+ .acquisition_time = 1,
+ .averaging = 1,
+ .pen_down_acc_interval = 1,
+};
+#endif
+
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+ && defined(CONFIG_SND_SOC_WM8731_SPI)
+static struct bfin5xx_spi_chip spi_wm8731_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+static struct bfin5xx_spi_chip spidev_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+ || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+ || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+ {
+ .modalias = "spi_mmc_dummy",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 0,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "spi_mmc",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = CONFIG_SPI_MMC_CS_CHAN,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+#if defined(CONFIG_PBX)
+ {
+ .modalias = "fxs-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 8 - CONFIG_J11_JUMPER,
+ .controller_data = &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "fxo-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 8 - CONFIG_J19_JUMPER,
+ .controller_data = &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+ {
+ .modalias = "ad7877",
+ .platform_data = &bfin_ad7877_ts_info,
+ .irq = IRQ_PF8,
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 2,
+ .controller_data = &spi_ad7877_chip_info,
+ },
+#endif
+#if defined(CONFIG_SND_SOC_WM8731) || defined(CONFIG_SND_SOC_WM8731_MODULE) \
+ && defined(CONFIG_SND_SOC_WM8731_SPI)
+ {
+ .modalias = "wm8731",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 5,
+ .controller_data = &spi_wm8731_chip_info,
+ .mode = SPI_MODE_0,
+ },
+#endif
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 1,
+ .controller_data = &spidev_chip_info,
+ },
+#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+ {
+ .modalias = "bfin-lq035q1-spi",
+ .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 1,
+ .controller_data = &lq035q1_spi_chip_info,
+ .mode = SPI_CPHA | SPI_CPOL,
+ },
+#endif
+};
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* SPI controller data */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+ .pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+ [0] = {
+ .start = SPI0_REGBASE,
+ .end = SPI0_REGBASE + 0xFF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CH_SPI,
+ .end = CH_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_spi0_device = {
+ .name = "bfin-spi",
+ .id = 0, /* Bus number */
+ .num_resources = ARRAY_SIZE(bfin_spi0_resource),
+ .resource = bfin_spi0_resource,
+ .dev = {
+ .platform_data = &bfin_spi0_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+ {
+ .start = 0xFFC02000,
+ .end = 0xFFC020FF,
+ .flags = IORESOURCE_MEM,
+ },
+#endif
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+static struct resource bfin_sir_resources[] = {
+#ifdef CONFIG_BFIN_SIR0
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+#endif
+#ifdef CONFIG_BFIN_SIR1
+ {
+ .start = 0xFFC02000,
+ .end = 0xFFC020FF,
+ .flags = IORESOURCE_MEM,
+ },
+#endif
+};
+
+static struct platform_device bfin_sir_device = {
+ .name = "bfin_sir",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bfin_sir_resources),
+ .resource = bfin_sir_resources,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+ [0] = {
+ .start = TWI0_REGBASE,
+ .end = TWI0_REGBASE,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_TWI,
+ .end = IRQ_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+ .name = "i2c-bfin-twi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bfin_twi0_resource),
+ .resource = bfin_twi0_resource,
+};
+#endif
+
+#ifdef CONFIG_I2C_BOARDINFO
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
+ {
+ I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+ },
+#endif
+#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
+ {
+ I2C_BOARD_INFO("pcf8574_keypad", 0x27),
+ .irq = IRQ_PF8,
+ },
+#endif
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 1,
+};
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+ {BTN_0, GPIO_PG0, 1, "gpio-keys: BTN0"},
+ {BTN_1, GPIO_PG13, 1, "gpio-keys: BTN1"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+ .buttons = bfin_gpio_keys_table,
+ .nbuttons = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+ .name = "gpio-keys",
+ .dev = {
+ .platform_data = &bfin_gpio_keys_data,
+ },
+};
+#endif
+
+static struct resource bfin_gpios_resources = {
+ .start = 0,
+ .end = MAX_BLACKFIN_GPIOS - 1,
+ .flags = IORESOURCE_IRQ,
+};
+
+static struct platform_device bfin_gpios_device = {
+ .name = "simple-gpio",
+ .id = -1,
+ .num_resources = 1,
+ .resource = &bfin_gpios_resources,
+};
+
+static const unsigned int cclk_vlev_datasheet[] =
+{
+ VRPAIR(VLEV_100, 400000000),
+ VRPAIR(VLEV_105, 426000000),
+ VRPAIR(VLEV_110, 500000000),
+ VRPAIR(VLEV_115, 533000000),
+ VRPAIR(VLEV_120, 600000000),
+};
+
+static struct bfin_dpmc_platform_data bfin_dmpc_vreg_data = {
+ .tuple_tab = cclk_vlev_datasheet,
+ .tabsize = ARRAY_SIZE(cclk_vlev_datasheet),
+ .vr_settling_time = 25 /* us */,
+};
+
+static struct platform_device bfin_dpmc = {
+ .name = "bfin dpmc",
+ .dev = {
+ .platform_data = &bfin_dmpc_vreg_data,
+ },
+};
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+ .mode = LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+ .use_bl = 1,
+ .gpio_bl = GPIO_PG12,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+ {
+ .start = IRQ_PPI_ERROR,
+ .end = IRQ_PPI_ERROR,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_lq035q1_device = {
+ .name = "bfin-lq035q1",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bfin_lq035q1_resources),
+ .resource = bfin_lq035q1_resources,
+ .dev = {
+ .platform_data = &bfin_lq035q1_data,
+ },
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+
+ &bfin_dpmc,
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+ &bf5xx_nand_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+ &musb_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+ &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &bfin_spi0_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+ &bfin_lq035q1_device,
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+ &bfin_sir_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+ &i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+ &bfin_sport0_uart_device,
+ &bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+ &bfin_device_gpiokeys,
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+ &ezbrd_flash_device,
+#endif
+
+ &bfin_gpios_device,
+};
+
+static int __init stamp_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __func__);
+
+#ifdef CONFIG_I2C_BOARDINFO
+ i2c_register_board_info(0, bfin_i2c_board_info,
+ ARRAY_SIZE(bfin_i2c_board_info));
+#endif
+
+ platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+ spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+ return 0;
+}
+
+arch_initcall(stamp_init);
+
+void native_machine_restart(char *cmd)
+{
+ /* workaround reboot hang when booting from SPI */
+ if ((bfin_read_SYSCR() & 0x7) == 0x3)
+ bfin_gpio_reset_spi0_ssel1();
+}
+
+void bfin_get_ether_addr(char *addr)
+{
+ /* the MAC is stored in OTP memory page 0xDF */
+ u32 ret;
+ u64 otp_mac;
+ u32 (*otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)0xEF00001A;
+
+ ret = otp_read(0xDF, 0x00, &otp_mac);
+ if (!(ret & 0x1)) {
+ char *otp_mac_p = (char *)&otp_mac;
+ for (ret = 0; ret < 6; ++ret)
+ addr[ret] = otp_mac_p[5 - ret];
+ }
+}
+EXPORT_SYMBOL(bfin_get_ether_addr);
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index 762f754c06c..8ee2b744e23 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -42,10 +42,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb/sl811.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
#include <linux/usb/musb.h>
-#endif
-#include <asm/cplb.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>
@@ -129,6 +126,16 @@ static struct resource musb_resources[] = {
},
};
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 0,
+ .dyn_fifo = 0,
+ .soft_con = 1,
+ .dma = 1,
+ .num_eps = 7,
+ .dma_channels = 7,
+ .gpio_vrsel = GPIO_PG13,
+};
+
static struct musb_hdrc_platform_data musb_plat = {
#if defined(CONFIG_USB_MUSB_OTG)
.mode = MUSB_OTG,
@@ -137,7 +144,7 @@ static struct musb_hdrc_platform_data musb_plat = {
#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
.mode = MUSB_PERIPHERAL,
#endif
- .multipoint = 0,
+ .config = &musb_config,
};
static u64 musb_dmamask = ~(u32)0;
@@ -218,7 +225,7 @@ static struct mtd_partition partition_info[] = {
{
.name = "linux kernel(nand)",
.offset = 0,
- .size = 4 * SIZE_1M,
+ .size = 4 * 1024 * 1024,
},
{
.name = "file system(nand)",
@@ -846,6 +853,38 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+#include <linux/input.h>
+#include <asm/bfin_rotary.h>
+
+static struct bfin_rotary_platform_data bfin_rotary_data = {
+ /*.rotary_up_key = KEY_UP,*/
+ /*.rotary_down_key = KEY_DOWN,*/
+ .rotary_rel_code = REL_WHEEL,
+ .rotary_button_key = KEY_ENTER,
+ .debounce = 10, /* 0..17 */
+ .mode = ROT_QUAD_ENC | ROT_DEBE,
+};
+
+static struct resource bfin_rotary_resources[] = {
+ {
+ .start = IRQ_CNT,
+ .end = IRQ_CNT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_rotary_device = {
+ .name = "bfin-rotary",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bfin_rotary_resources),
+ .resource = bfin_rotary_resources,
+ .dev = {
+ .platform_data = &bfin_rotary_data,
+ },
+};
+#endif
+
static struct resource bfin_gpios_resources = {
.start = 0,
.end = MAX_BLACKFIN_GPIOS - 1,
@@ -962,6 +1001,10 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_device_gpiokeys,
#endif
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+ &bfin_rotary_device,
+#endif
+
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&ezkit_flash_device,
#endif
diff --git a/arch/blackfin/mach-bf527/head.S b/arch/blackfin/mach-bf527/head.S
index 28c48619120..6588170e384 100644
--- a/arch/blackfin/mach-bf527/head.S
+++ b/arch/blackfin/mach-bf527/head.S
@@ -87,6 +87,9 @@ ENTRY(_start_dma_code)
r1 = PLL_BYPASS; /* Bypass the PLL? */
r1 = r1 << 8; /* Shift it over */
r0 = r1 | r0; /* add them all together */
+#ifdef ANOMALY_05000265
+ r0 = BITSET(r0, 15); /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
p0.h = hi(PLL_CTL);
p0.l = lo(PLL_CTL); /* Load the address */
diff --git a/arch/blackfin/mach-bf527/include/mach/anomaly.h b/arch/blackfin/mach-bf527/include/mach/anomaly.h
index b7b166f4f06..62373e61c58 100644
--- a/arch/blackfin/mach-bf527/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf527/include/mach/anomaly.h
@@ -7,12 +7,24 @@
*/
/* This file shoule be up to date with:
- * - Revision C, 01/25/2008; ADSP-BF527 Blackfin Processor Anomaly List
+ * - Revision B, 08/12/2008; ADSP-BF526 Blackfin Processor Anomaly List
+ * - Revision E, 08/18/2008; ADSP-BF527 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
#define _MACH_ANOMALY_H_
+#if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
+# define ANOMALY_BF526 1
+#else
+# define ANOMALY_BF526 0
+#endif
+#if defined(__ADSPBF523__) || defined(__ADSPBF525__) || defined(__ADSPBF527__)
+# define ANOMALY_BF527 1
+#else
+# define ANOMALY_BF527 0
+#endif
+
/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
#define ANOMALY_05000074 (1)
/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
@@ -23,68 +35,124 @@
#define ANOMALY_05000245 (1)
/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
#define ANOMALY_05000265 (1)
-/* New Feature: EMAC TX DMA Word Alignment */
-#define ANOMALY_05000285 (1)
+/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
+#define ANOMALY_05000310 (1)
/* Errors when SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
+#define ANOMALY_05000312 (ANOMALY_BF527)
+/* PPI Is Level-Sensitive on First Transfer In Single Frame Sync Modes */
+#define ANOMALY_05000313 (__SILICON_REVISION__ < 2)
/* Incorrect Access of OTP_STATUS During otp_write() Function */
-#define ANOMALY_05000328 (1)
+#define ANOMALY_05000328 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
-#define ANOMALY_05000337 (1)
+#define ANOMALY_05000337 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
-#define ANOMALY_05000341 (1)
+#define ANOMALY_05000341 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* TWI May Not Operate Correctly Under Certain Signal Termination Conditions */
-#define ANOMALY_05000342 (1)
+#define ANOMALY_05000342 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* USB Calibration Value Is Not Initialized */
-#define ANOMALY_05000346 (1)
+#define ANOMALY_05000346 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* USB Calibration Value to use */
+#define ANOMALY_05000346_value 0xE510
/* Preboot Routine Incorrectly Alters Reset Value of USB Register */
-#define ANOMALY_05000347 (1)
+#define ANOMALY_05000347 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Security Features Are Not Functional */
-#define ANOMALY_05000348 (__SILICON_REVISION__ < 1)
+#define ANOMALY_05000348 (ANOMALY_BF527 && __SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Function Performs Improper System Reset */
+#define ANOMALY_05000353 (ANOMALY_BF526)
/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
-#define ANOMALY_05000355 (1)
+#define ANOMALY_05000355 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (1)
+#define ANOMALY_05000357 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Incorrect Revision Number in DSPID Register */
-#define ANOMALY_05000364 (__SILICON_REVISION__ > 0)
+#define ANOMALY_05000364 (ANOMALY_BF527 && __SILICON_REVISION__ == 1)
/* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
#define ANOMALY_05000366 (1)
-/* New Feature: Higher Default CCLK Rate */
-#define ANOMALY_05000368 (1)
+/* Incorrect Default CSEL Value in PLL_DIV */
+#define ANOMALY_05000368 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Authentication Fails To Initiate */
-#define ANOMALY_05000376 (__SILICON_REVISION__ > 0)
+#define ANOMALY_05000376 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* Data Read From L3 Memory by USB DMA May be Corrupted */
-#define ANOMALY_05000380 (1)
-/* USB Full-speed Mode not Fully Tested */
-#define ANOMALY_05000381 (1)
-/* New Feature: Boot from OTP Memory */
-#define ANOMALY_05000385 (1)
-/* New Feature: bfrom_SysControl() Routine */
-#define ANOMALY_05000386 (1)
-/* New Feature: Programmable Preboot Settings */
-#define ANOMALY_05000387 (1)
+#define ANOMALY_05000380 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* 8-Bit NAND Flash Boot Mode Not Functional */
+#define ANOMALY_05000382 (__SILICON_REVISION__ < 2)
+/* Host Must Not Read Back During Host DMA Boot */
+#define ANOMALY_05000384 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Boot from OTP Memory Not Functional */
+#define ANOMALY_05000385 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Routine Not Functional */
+#define ANOMALY_05000386 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Programmable Preboot Settings Not Functional */
+#define ANOMALY_05000387 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* CRC32 Checksum Support Not Functional */
+#define ANOMALY_05000388 (__SILICON_REVISION__ < 2)
/* Reset Vector Must Not Be in SDRAM Memory Space */
-#define ANOMALY_05000389 (1)
-/* New Feature: pTempCurrent Added to ADI_BOOT_DATA Structure */
-#define ANOMALY_05000392 (1)
-/* New Feature: dTempByteCount Value Increased in ADI_BOOT_DATA Structure */
-#define ANOMALY_05000393 (1)
-/* New Feature: Log Buffer Functionality */
-#define ANOMALY_05000394 (1)
-/* New Feature: Hook Routine Functionality */
-#define ANOMALY_05000395 (1)
-/* New Feature: Header Indirect Bit */
-#define ANOMALY_05000396 (1)
-/* New Feature: BK_ONES, BK_ZEROS, and BK_DATECODE Constants */
-#define ANOMALY_05000397 (1)
-/* New Feature: SWRESET, DFRESET and WDRESET Bits Added to SYSCR Register */
-#define ANOMALY_05000398 (1)
-/* New Feature: BCODE_NOBOOT Added to BCODE Field of SYSCR Register */
-#define ANOMALY_05000399 (1)
+#define ANOMALY_05000389 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000392 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000393 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Log Buffer Not Functional */
+#define ANOMALY_05000394 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Hook Routine Not Functional */
+#define ANOMALY_05000395 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Header Indirect Bit Not Functional */
+#define ANOMALY_05000396 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
+#define ANOMALY_05000397 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* SWRESET, DFRESET and WDRESET Bits in the SYSCR Register Not Functional */
+#define ANOMALY_05000398 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* BCODE_NOBOOT in BCODE Field of SYSCR Register Not Functional */
+#define ANOMALY_05000399 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
/* PPI Data Signals D0 and D8 do not Tristate After Disabling PPI */
-#define ANOMALY_05000401 (1)
+#define ANOMALY_05000401 (__SILICON_REVISION__ < 2)
+/* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
+#define ANOMALY_05000403 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Disallows Certain User Interrupts */
+#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Does Not Save/Restore Full Context */
+#define ANOMALY_05000405 (1)
+/* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
+#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+/* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
+#define ANOMALY_05000408 (1)
+/* Lockbox firmware leaves MDMA0 channel enabled */
+#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+/* Incorrect Default Internal Voltage Regulator Setting */
+#define ANOMALY_05000410 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
+#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+/* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
+#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+/* DEB2_URGENT Bit Not Functional */
+#define ANOMALY_05000415 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
+/* SPORT0 Ignores External TSCLK0 on PG14 When TMR6 is an Output */
+#define ANOMALY_05000417 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* tSFSPE and tHFSPE Do Not Meet Data Sheet Specifications */
+#define ANOMALY_05000418 (__SILICON_REVISION__ < 2)
+/* USB PLL_STABLE Bit May Not Accurately Reflect the USB PLL's Status */
+#define ANOMALY_05000420 (__SILICON_REVISION__ < 2)
+/* TWI Fall Time (Tof) May Violate the Minimum I2C Specification */
+#define ANOMALY_05000421 (1)
+/* TWI Input Capacitance (Ci) May Violate the Maximum I2C Specification */
+#define ANOMALY_05000422 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+/* Certain Ethernet Frames With Errors are Misclassified in RMII Mode */
+#define ANOMALY_05000423 (__SILICON_REVISION__ < 2)
+/* Internal Voltage Regulator Not Trimmed */
+#define ANOMALY_05000424 (ANOMALY_BF527 && __SILICON_REVISION__ < 2)
+/* Multichannel SPORT Channel Misalignment Under Specific Configuration */
+#define ANOMALY_05000425 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000426 (1)
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Reflects Buffer Status Instead of IRQ Status */
+#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+/* Software System Reset Corrupts PLL_LOCKCNT Register */
+#define ANOMALY_05000430 (ANOMALY_BF527 && __SILICON_REVISION__ > 1)
+/* bfrom_SysControl() Does Not Clear SIC_IWR1 Before Executing PLL Programming Sequence */
+#define ANOMALY_05000432 (ANOMALY_BF526)
/* Anomalies that don't exist on this proc */
#define ANOMALY_05000125 (0)
@@ -97,6 +165,8 @@
#define ANOMALY_05000263 (0)
#define ANOMALY_05000266 (0)
#define ANOMALY_05000273 (0)
+#define ANOMALY_05000285 (0)
+#define ANOMALY_05000307 (0)
#define ANOMALY_05000311 (0)
#define ANOMALY_05000323 (0)
#define ANOMALY_05000363 (0)
diff --git a/arch/blackfin/mach-bf527/include/mach/bf527.h b/arch/blackfin/mach-bf527/include/mach/bf527.h
index 056eb4b9cd2..144f08d3f8e 100644
--- a/arch/blackfin/mach-bf527/include/mach/bf527.h
+++ b/arch/blackfin/mach-bf527/include/mach/bf527.h
@@ -30,8 +30,6 @@
#ifndef __MACH_BF527_H__
#define __MACH_BF527_H__
-#define SUPPORTED_REVID 2
-
#define OFFSET_(x) ((x) & 0x0000FFFF)
/*some misc defines*/
@@ -112,16 +110,31 @@
#ifdef CONFIG_BF527
#define CPU "BF527"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF526
+#define CPU "BF526"
+#define CPUID 0x27e4
#endif
#ifdef CONFIG_BF525
#define CPU "BF525"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF524
+#define CPU "BF524"
+#define CPUID 0x27e4
+#endif
+#ifdef CONFIG_BF523
+#define CPU "BF523"
+#define CPUID 0x27e4
#endif
#ifdef CONFIG_BF522
#define CPU "BF522"
+#define CPUID 0x27e4
#endif
+
#ifndef CPU
-#define CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
#endif
#endif /* __MACH_BF527_H__ */
diff --git a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
index 2526b6ed6fa..75722d6008b 100644
--- a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
@@ -78,6 +78,9 @@
# define CONFIG_UART1_RTS_PIN -1
# endif
#endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
/*
* The pin configuration is different from schematic
*/
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
struct bfin_serial_res {
unsigned long uart_base_addr;
int uart_irq;
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
#endif
};
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
#define DRIVER_NAME "bfin-uart"
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
index 6ac2ed7026e..68b55d03fed 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
@@ -1840,6 +1840,33 @@
#define DPRESCALE 0xf /* Load Counter Register */
+/* CNT_COMMAND bit field options */
+
+#define W1LCNT_ZERO 0x0001 /* write 1 to load CNT_COUNTER with zero */
+#define W1LCNT_MIN 0x0004 /* write 1 to load CNT_COUNTER from CNT_MIN */
+#define W1LCNT_MAX 0x0008 /* write 1 to load CNT_COUNTER from CNT_MAX */
+
+#define W1LMIN_ZERO 0x0010 /* write 1 to load CNT_MIN with zero */
+#define W1LMIN_CNT 0x0020 /* write 1 to load CNT_MIN from CNT_COUNTER */
+#define W1LMIN_MAX 0x0080 /* write 1 to load CNT_MIN from CNT_MAX */
+
+#define W1LMAX_ZERO 0x0100 /* write 1 to load CNT_MAX with zero */
+#define W1LMAX_CNT 0x0200 /* write 1 to load CNT_MAX from CNT_COUNTER */
+#define W1LMAX_MIN 0x0400 /* write 1 to load CNT_MAX from CNT_MIN */
+
+/* CNT_CONFIG bit field options */
+
+#define CNTMODE_QUADENC 0x0000 /* quadrature encoder mode */
+#define CNTMODE_BINENC 0x0100 /* binary encoder mode */
+#define CNTMODE_UDCNT 0x0200 /* up/down counter mode */
+#define CNTMODE_DIRCNT 0x0400 /* direction counter mode */
+#define CNTMODE_DIRTMR 0x0500 /* direction timer mode */
+
+#define BNDMODE_COMP 0x0000 /* boundary compare mode */
+#define BNDMODE_ZERO 0x1000 /* boundary compare and zero mode */
+#define BNDMODE_CAPT 0x2000 /* boundary capture mode */
+#define BNDMODE_AEXT 0x3000 /* boundary auto-extend mode */
+
/* Bit masks for OTP_CONTROL */
#define FUSE_FADDR 0x1ff /* OTP/Fuse Address */
diff --git a/arch/blackfin/mach-bf527/include/mach/portmux.h b/arch/blackfin/mach-bf527/include/mach/portmux.h
index ae4d205bfcf..7f6da2c386b 100644
--- a/arch/blackfin/mach-bf527/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf527/include/mach/portmux.h
@@ -67,6 +67,10 @@
#define P_UART1_RX (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(1))
#endif
+#define P_CNT_CZM (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(3))
+#define P_CNT_CDG (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(3))
+#define P_CNT_CUD (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(3))
+
#define P_HWAIT (P_DONTCARE)
#define P_SPI0_SS (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
index c66a68f3023..72ac3ac8ef7 100644
--- a/arch/blackfin/mach-bf533/boards/H8606.c
+++ b/arch/blackfin/mach-bf533/boards/H8606.c
@@ -9,7 +9,7 @@
* Modified:
* Copyright 2005 National ICT Australia (NICTA)
* Copyright 2004-2006 Analog Devices Inc
- * Copyright 2007 HV Sistemas S.L.
+ * Copyright 2007,2008 HV Sistemas S.L.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
@@ -64,18 +64,18 @@ static struct platform_device rtc_device = {
static struct resource dm9000_resources[] = {
[0] = {
.start = 0x20300000,
- .end = 0x20300000 + 1,
+ .end = 0x20300002,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 0x20300000 + 4,
- .end = 0x20300000 + 5,
+ .start = 0x20300004,
+ .end = 0x20300006,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_PF10,
.end = IRQ_PF10,
- .flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE),
+ .flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IRQF_SHARED | IRQF_TRIGGER_HIGH),
},
};
@@ -140,18 +140,22 @@ static struct platform_device net2272_bfin_device = {
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
static struct mtd_partition bfin_spi_flash_partitions[] = {
{
- .name = "bootloader(spi)",
- .size = 0x00060000,
+ .name = "bootloader (spi)",
+ .size = 0x40000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
}, {
- .name = "linux kernel(spi)",
- .size = 0x100000,
- .offset = 0x60000
+ .name = "fpga (spi)",
+ .size = 0x30000,
+ .offset = 0x40000
}, {
- .name = "file system(spi)",
- .size = 0x6a0000,
- .offset = 0x00160000,
+ .name = "linux kernel (spi)",
+ .size = 0x150000,
+ .offset = 0x70000
+ }, {
+ .name = "jffs2 root file system (spi)",
+ .size = 0x640000,
+ .offset = 0x1c0000,
}
};
@@ -340,7 +344,7 @@ static struct platform_device bfin_sir_device = {
static struct plat_serial8250_port serial8250_platform_data [] = {
{
- .membase = 0x20200000,
+ .membase = (void *)0x20200000,
.mapbase = 0x20200000,
.irq = IRQ_PF8,
.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
@@ -348,7 +352,7 @@ static struct plat_serial8250_port serial8250_platform_data [] = {
.regshift = 1,
.uartclk = 66666667,
}, {
- .membase = 0x20200010,
+ .membase = (void *)0x20200010,
.mapbase = 0x20200010,
.irq = IRQ_PF8,
.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S
index 01b2b7ead5a..619685b94d9 100644
--- a/arch/blackfin/mach-bf533/head.S
+++ b/arch/blackfin/mach-bf533/head.S
@@ -78,6 +78,9 @@ ENTRY(_start_dma_code)
r1 = PLL_BYPASS; /* Bypass the PLL? */
r1 = r1 << 8; /* Shift it over */
r0 = r1 | r0; /* add them all together */
+#ifdef ANOMALY_05000265
+ r0 = BITSET(r0, 15); /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
p0.h = hi(PLL_CTL);
p0.l = lo(PLL_CTL); /* Load the address */
diff --git a/arch/blackfin/mach-bf533/include/mach/anomaly.h b/arch/blackfin/mach-bf533/include/mach/anomaly.h
index 8f7ea112fd3..f544fc56959 100644
--- a/arch/blackfin/mach-bf533/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf533/include/mach/anomaly.h
@@ -7,7 +7,7 @@
*/
/* This file shoule be up to date with:
- * - Revision C, 02/08/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+ * - Revision D, 06/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
@@ -97,11 +97,11 @@
/* UART STB Bit Incorrectly Affects Receiver Setting */
#define ANOMALY_05000231 (__SILICON_REVISION__ < 5)
/* PPI_FS3 Is Not Driven in 2 or 3 Internal Frame Sync Transmit Modes */
-#define ANOMALY_05000233 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000233 (__SILICON_REVISION__ < 6)
/* Incorrect Revision Number in DSPID Register */
#define ANOMALY_05000234 (__SILICON_REVISION__ == 4)
/* DF Bit in PLL_CTL Register Does Not Respond to Hardware Reset */
-#define ANOMALY_05000242 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000242 (__SILICON_REVISION__ < 5)
/* If I-Cache Is On, CSYNC/SSYNC/IDLE Around Change of Control Causes Failures */
#define ANOMALY_05000244 (__SILICON_REVISION__ < 5)
/* Spurious Hardware Error from an Access in the Shadow of a Conditional Branch */
@@ -131,7 +131,7 @@
/* CSYNC/SSYNC/IDLE Causes Infinite Stall in Penultimate Instruction in Hardware Loop */
#define ANOMALY_05000264 (__SILICON_REVISION__ < 5)
/* Sensitivity To Noise with Slow Input Edge Rates on External SPORT TX and RX Clocks */
-#define ANOMALY_05000265 (__SILICON_REVISION__ < 5)
+#define ANOMALY_05000265 (1)
/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Increase */
#define ANOMALY_05000269 (__SILICON_REVISION__ < 5)
/* High I/O Activity Causes Output Voltage of Internal Voltage Regulator (Vddint) to Decrease */
@@ -141,56 +141,59 @@
/* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
#define ANOMALY_05000272 (1)
/* Writes to Synchronous SDRAM Memory May Be Lost */
-#define ANOMALY_05000273 (1)
+#define ANOMALY_05000273 (__SILICON_REVISION__ < 6)
/* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
#define ANOMALY_05000276 (1)
/* Writes to an I/O Data Register One SCLK Cycle after an Edge Is Detected May Clear Interrupt */
-#define ANOMALY_05000277 (1)
+#define ANOMALY_05000277 (__SILICON_REVISION__ < 6)
/* Disabling Peripherals with DMA Running May Cause DMA System Instability */
-#define ANOMALY_05000278 (1)
+#define ANOMALY_05000278 (__SILICON_REVISION__ < 6)
/* False Hardware Error Exception When ISR Context Is Not Restored */
-#define ANOMALY_05000281 (1)
+#define ANOMALY_05000281 (__SILICON_REVISION__ < 6)
/* Memory DMA Corruption with 32-Bit Data and Traffic Control */
-#define ANOMALY_05000282 (1)
+#define ANOMALY_05000282 (__SILICON_REVISION__ < 6)
/* System MMR Write Is Stalled Indefinitely When Killed in a Particular Stage */
-#define ANOMALY_05000283 (1)
+#define ANOMALY_05000283 (__SILICON_REVISION__ < 6)
/* SPORTs May Receive Bad Data If FIFOs Fill Up */
-#define ANOMALY_05000288 (1)
+#define ANOMALY_05000288 (__SILICON_REVISION__ < 6)
/* Memory-To-Memory DMA Source/Destination Descriptors Must Be in Same Memory Space */
-#define ANOMALY_05000301 (1)
+#define ANOMALY_05000301 (__SILICON_REVISION__ < 6)
/* SSYNCs After Writes To DMA MMR Registers May Not Be Handled Correctly */
#define ANOMALY_05000302 (__SILICON_REVISION__ < 5)
/* New Feature: Additional Hysteresis on SPORT Input Pins (Not Available On Older Silicon) */
#define ANOMALY_05000305 (__SILICON_REVISION__ < 5)
/* New Feature: Additional PPI Frame Sync Sampling Options (Not Available On Older Silicon) */
#define ANOMALY_05000306 (__SILICON_REVISION__ < 5)
+/* SCKELOW Bit Does Not Maintain State Through Hibernate */
+#define ANOMALY_05000307 (1)
/* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
#define ANOMALY_05000310 (1)
/* Erroneous Flag (GPIO) Pin Operations under Specific Sequences */
-#define ANOMALY_05000311 (1)
+#define ANOMALY_05000311 (__SILICON_REVISION__ < 6)
/* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
+#define ANOMALY_05000312 (__SILICON_REVISION__ < 6)
/* PPI Is Level-Sensitive on First Transfer */
-#define ANOMALY_05000313 (1)
+#define ANOMALY_05000313 (__SILICON_REVISION__ < 6)
/* Killed System MMR Write Completes Erroneously On Next System MMR Access */
-#define ANOMALY_05000315 (1)
+#define ANOMALY_05000315 (__SILICON_REVISION__ < 6)
/* Internal Voltage Regulator Values of 1.05V, 1.10V and 1.15V Not Allowed for LQFP Packages */
-#define ANOMALY_05000319 (ANOMALY_BF531 || ANOMALY_BF532)
+#define ANOMALY_05000319 ((ANOMALY_BF531 || ANOMALY_BF532) && __SILICON_REVISION__ < 6)
/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
-#define ANOMALY_05000357 (1)
+#define ANOMALY_05000357 (__SILICON_REVISION__ < 6)
/* UART Break Signal Issues */
#define ANOMALY_05000363 (__SILICON_REVISION__ < 5)
/* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
#define ANOMALY_05000366 (1)
/* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (__SILICON_REVISION__ < 6)
/* PPI Does Not Start Properly In Specific Mode */
-#define ANOMALY_05000400 (__SILICON_REVISION__ >= 5)
+#define ANOMALY_05000400 (__SILICON_REVISION__ == 5)
/* SSYNC Stalls Processor when Executed from Non-Cacheable Memory */
-#define ANOMALY_05000402 (__SILICON_REVISION__ >= 5)
+#define ANOMALY_05000402 (__SILICON_REVISION__ == 5)
/* Level-Sensitive External GPIO Wakeups May Cause Indefinite Stall */
#define ANOMALY_05000403 (1)
-
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
/* These anomalies have been "phased" out of analog.com anomaly sheets and are
* here to show running on older silicon just isn't feasible.
@@ -268,5 +271,7 @@
/* Anomalies that don't exist on this proc */
#define ANOMALY_05000266 (0)
#define ANOMALY_05000323 (0)
+#define ANOMALY_05000353 (1)
+#define ANOMALY_05000386 (1)
#endif
diff --git a/arch/blackfin/mach-bf533/include/mach/bf533.h b/arch/blackfin/mach-bf533/include/mach/bf533.h
index 12a41693199..dfc8c1ad2d7 100644
--- a/arch/blackfin/mach-bf533/include/mach/bf533.h
+++ b/arch/blackfin/mach-bf533/include/mach/bf533.h
@@ -30,8 +30,6 @@
#ifndef __MACH_BF533_H__
#define __MACH_BF533_H__
-#define SUPPORTED_REVID 2
-
#define OFFSET_(x) ((x) & 0x0000FFFF)
/*some misc defines*/
@@ -143,19 +141,19 @@
#ifdef CONFIG_BF533
#define CPU "BF533"
-#define CPUID 0x027a5000
+#define CPUID 0x27a5
#endif
#ifdef CONFIG_BF532
#define CPU "BF532"
-#define CPUID 0x0275A000
+#define CPUID 0x275A
#endif
#ifdef CONFIG_BF531
#define CPU "BF531"
-#define CPUID 0x027a5000
+#define CPUID 0x27a5
#endif
+
#ifndef CPU
-#define CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
#endif
#endif /* __MACH_BF533_H__ */
diff --git a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
index ebf592b59aa..34ab0e4e424 100644
--- a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
@@ -69,6 +69,8 @@
# endif
#endif
+#define BFIN_UART_TX_FIFO_SIZE 2
+
struct bfin_serial_port {
struct uart_port port;
unsigned int old_status;
@@ -83,7 +85,7 @@ struct bfin_serial_port {
unsigned int rx_dma_channel;
struct work_struct tx_dma_workqueue;
#else
-# if ANOMALY_05000230
+# if ANOMALY_05000363
unsigned int anomaly_threshold;
# endif
#endif
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
struct bfin_serial_res {
unsigned long uart_base_addr;
int uart_irq;
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
#define DRIVER_NAME "bfin-uart"
-int nr_ports = BFIN_UART_NR_PORTS;
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
{
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 8482d22321f..dc5a30849c1 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -51,7 +51,6 @@
#include <asm/reboot.h>
#include <asm/portmux.h>
#include <asm/dpmc.h>
-#include <linux/spi/ad7877.h>
/*
* Name the Board for the /proc/cpuinfo
@@ -555,6 +554,7 @@ static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
#endif
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+#include <linux/spi/ad7877.h>
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
.enable_dma = 0,
.bits_per_word = 16,
@@ -575,6 +575,28 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = {
};
#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7879) || defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+#include <linux/spi/ad7879.h>
+static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+
+static const struct ad7879_platform_data bfin_ad7879_ts_info = {
+ .model = 7879, /* Model = AD7879 */
+ .x_plate_ohms = 620, /* 620 Ohm from the touch datasheet */
+ .pressure_max = 10000,
+ .pressure_min = 0,
+ .first_conversion_delay = 3, /* wait 512us before do a first conversion */
+ .acquisition_time = 1, /* 4us acquisition time per sample */
+ .median = 2, /* do 8 measurements */
+ .averaging = 1, /* take the average of 4 middle samples */
+ .pen_down_acc_interval = 255, /* 9.4 ms */
+ .gpio_output = 1, /* configure AUX/VBAT/GPIO as GPIO output */
+ .gpio_default = 1, /* During initialization set GPIO = HIGH */
+};
+#endif
+
#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
static struct bfin5xx_spi_chip spidev_chip_info = {
.enable_dma = 0,
@@ -582,6 +604,13 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
};
#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 8,
+};
+#endif
+
#if defined(CONFIG_MTD_DATAFLASH) \
|| defined(CONFIG_MTD_DATAFLASH_MODULE)
@@ -721,6 +750,18 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
.controller_data = &spi_ad7877_chip_info,
},
#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7879) || defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+ {
+ .modalias = "ad7879",
+ .platform_data = &bfin_ad7879_ts_info,
+ .irq = IRQ_PF7,
+ .max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 1,
+ .controller_data = &spi_ad7879_chip_info,
+ .mode = SPI_CPHA | SPI_CPOL,
+ },
+#endif
#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
{
.modalias = "spidev",
@@ -730,6 +771,16 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
.controller_data = &spidev_chip_info,
},
#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+ {
+ .modalias = "bfin-lq035q1-spi",
+ .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 0,
+ .chip_select = 2,
+ .controller_data = &lq035q1_spi_chip_info,
+ .mode = SPI_CPHA | SPI_CPOL,
+ },
+#endif
};
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
@@ -777,6 +828,34 @@ static struct platform_device bfin_fb_adv7393_device = {
};
#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+ .mode = LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+ .use_bl = 0, /* let something else control the LCD Blacklight */
+ .gpio_bl = GPIO_PF7,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+ {
+ .start = IRQ_PPI_ERROR,
+ .end = IRQ_PPI_ERROR,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_lq035q1_device = {
+ .name = "bfin-lq035q1",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bfin_lq035q1_resources),
+ .resource = bfin_lq035q1_resources,
+ .dev = {
+ .platform_data = &bfin_lq035q1_data,
+ },
+};
+#endif
+
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
static struct resource bfin_uart_resources[] = {
#ifdef CONFIG_SERIAL_BFIN_UART0
@@ -997,6 +1076,10 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_fb_device,
#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+ &bfin_lq035q1_device,
+#endif
+
#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
&bfin_fb_adv7393_device,
#endif
diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S
index 12eb5cc571d..559a7eef7a3 100644
--- a/arch/blackfin/mach-bf537/head.S
+++ b/arch/blackfin/mach-bf537/head.S
@@ -87,6 +87,9 @@ ENTRY(_start_dma_code)
r1 = PLL_BYPASS; /* Bypass the PLL? */
r1 = r1 << 8; /* Shift it over */
r0 = r1 | r0; /* add them all together */
+#ifdef ANOMALY_05000265
+ r0 = BITSET(r0, 15); /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
p0.h = hi(PLL_CTL);
p0.l = lo(PLL_CTL); /* Load the address */
diff --git a/arch/blackfin/mach-bf537/include/mach/anomaly.h b/arch/blackfin/mach-bf537/include/mach/anomaly.h
index 8460ab9c324..c68992494f9 100644
--- a/arch/blackfin/mach-bf537/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf537/include/mach/anomaly.h
@@ -158,6 +158,8 @@
#define ANOMALY_05000266 (0)
#define ANOMALY_05000311 (0)
#define ANOMALY_05000323 (0)
+#define ANOMALY_05000353 (1)
#define ANOMALY_05000363 (0)
+#define ANOMALY_05000386 (1)
#endif
diff --git a/arch/blackfin/mach-bf537/include/mach/bf537.h b/arch/blackfin/mach-bf537/include/mach/bf537.h
index cfe2a221112..24d5c9d4232 100644
--- a/arch/blackfin/mach-bf537/include/mach/bf537.h
+++ b/arch/blackfin/mach-bf537/include/mach/bf537.h
@@ -30,8 +30,6 @@
#ifndef __MACH_BF537_H__
#define __MACH_BF537_H__
-#define SUPPORTED_REVID 2
-
/* Masks for generic ERROR IRQ demultiplexing used in int-priority-sc.c */
#define SPI_ERR_MASK (TXCOL | RBSY | MODF | TXE) /* SPI_STAT */
@@ -123,19 +121,19 @@
#ifdef CONFIG_BF537
#define CPU "BF537"
-#define CPUID 0x027c8000
+#define CPUID 0x27c8
#endif
#ifdef CONFIG_BF536
#define CPU "BF536"
-#define CPUID 0x027c8000
+#define CPUID 0x27c8
#endif
#ifdef CONFIG_BF534
#define CPU "BF534"
-#define CPUID 0x027c6000
+#define CPUID 0x27c6
#endif
+
#ifndef CPU
-#define CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
#endif
#endif /* __MACH_BF537_H__ */
diff --git a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
index 1bf56ffa22f..b3f87e1d16a 100644
--- a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
@@ -78,6 +78,9 @@
# define CONFIG_UART1_RTS_PIN -1
# endif
#endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
/*
* The pin configuration is different from schematic
*/
@@ -119,7 +122,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
struct bfin_serial_res {
unsigned long uart_base_addr;
int uart_irq;
@@ -164,8 +166,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
#endif
};
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
#define DRIVER_NAME "bfin-uart"
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
diff --git a/arch/blackfin/mach-bf548/boards/cm_bf548.c b/arch/blackfin/mach-bf548/boards/cm_bf548.c
index ce934ee174e..24192aaa927 100644
--- a/arch/blackfin/mach-bf548/boards/cm_bf548.c
+++ b/arch/blackfin/mach-bf548/boards/cm_bf548.c
@@ -36,11 +36,8 @@
#include <linux/spi/flash.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
#include <linux/usb/musb.h>
-#endif
#include <asm/bfin5xx_spi.h>
-#include <asm/cplb.h>
#include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/nand.h>
@@ -175,6 +172,7 @@ static struct resource bfin_uart_resources[] = {
{
.start = 0xFFC03100,
.end = 0xFFC031FF,
+ .flags = IORESOURCE_MEM,
},
#endif
};
@@ -268,6 +266,16 @@ static struct resource musb_resources[] = {
},
};
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 0,
+ .dyn_fifo = 0,
+ .soft_con = 1,
+ .dma = 1,
+ .num_eps = 7,
+ .dma_channels = 7,
+ .gpio_vrsel = GPIO_PH6,
+};
+
static struct musb_hdrc_platform_data musb_plat = {
#if defined(CONFIG_USB_MUSB_OTG)
.mode = MUSB_OTG,
@@ -276,7 +284,7 @@ static struct musb_hdrc_platform_data musb_plat = {
#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
.mode = MUSB_PERIPHERAL,
#endif
- .multipoint = 0,
+ .config = &musb_config,
};
static u64 musb_dmamask = ~(u32)0;
@@ -321,12 +329,12 @@ static struct mtd_partition partition_info[] = {
{
.name = "linux kernel(nand)",
.offset = 0,
- .size = 4 * SIZE_1M,
+ .size = 4 * 1024 * 1024,
},
{
.name = "file system(nand)",
- .offset = 4 * SIZE_1M,
- .size = (256 - 4) * SIZE_1M,
+ .offset = 4 * 1024 * 1024,
+ .size = (256 - 4) * 1024 * 1024,
},
};
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 39357693046..5288187a3ac 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -38,11 +38,8 @@
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
#include <linux/usb/musb.h>
-#endif
#include <asm/bfin5xx_spi.h>
-#include <asm/cplb.h>
#include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/nand.h>
@@ -186,6 +183,37 @@ static struct platform_device bf54x_kpad_device = {
};
#endif
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+#include <asm/bfin_rotary.h>
+
+static struct bfin_rotary_platform_data bfin_rotary_data = {
+ /*.rotary_up_key = KEY_UP,*/
+ /*.rotary_down_key = KEY_DOWN,*/
+ .rotary_rel_code = REL_WHEEL,
+ .rotary_button_key = KEY_ENTER,
+ .debounce = 10, /* 0..17 */
+ .mode = ROT_QUAD_ENC | ROT_DEBE,
+};
+
+static struct resource bfin_rotary_resources[] = {
+ {
+ .start = IRQ_CNT,
+ .end = IRQ_CNT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_rotary_device = {
+ .name = "bfin-rotary",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bfin_rotary_resources),
+ .resource = bfin_rotary_resources,
+ .dev = {
+ .platform_data = &bfin_rotary_data,
+ },
+};
+#endif
+
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
static struct platform_device rtc_device = {
.name = "rtc-bfin",
@@ -314,6 +342,16 @@ static struct resource musb_resources[] = {
},
};
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 0,
+ .dyn_fifo = 0,
+ .soft_con = 1,
+ .dma = 1,
+ .num_eps = 7,
+ .dma_channels = 7,
+ .gpio_vrsel = GPIO_PE7,
+};
+
static struct musb_hdrc_platform_data musb_plat = {
#if defined(CONFIG_USB_MUSB_OTG)
.mode = MUSB_OTG,
@@ -322,7 +360,7 @@ static struct musb_hdrc_platform_data musb_plat = {
#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
.mode = MUSB_PERIPHERAL,
#endif
- .multipoint = 0,
+ .config = &musb_config,
};
static u64 musb_dmamask = ~(u32)0;
@@ -367,7 +405,7 @@ static struct mtd_partition partition_info[] = {
{
.name = "linux kernel(nand)",
.offset = 0,
- .size = 4 * SIZE_1M,
+ .size = 4 * 1024 * 1024,
},
{
.name = "file system(nand)",
@@ -424,7 +462,7 @@ static struct mtd_partition ezkit_partitions[] = {
.offset = 0,
}, {
.name = "linux kernel(nor)",
- .size = 0x1C0000,
+ .size = 0x400000,
.offset = MTDPART_OFS_APPEND,
}, {
.name = "file system(nor)",
@@ -441,7 +479,7 @@ static struct physmap_flash_data ezkit_flash_data = {
static struct resource ezkit_flash_resource = {
.start = 0x20000000,
- .end = 0x20ffffff,
+ .end = 0x21ffffff,
.flags = IORESOURCE_MEM,
};
@@ -551,7 +589,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
{
.modalias = "ad7877",
.platform_data = &bfin_ad7877_ts_info,
- .irq = IRQ_PJ11,
+ .irq = IRQ_PJ11, /* newer boards (Rev 1.4+) use IRQ_PB4 */
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
.bus_num = 0,
.chip_select = 2,
@@ -810,6 +848,10 @@ static struct platform_device *ezkit_devices[] __initdata = {
&bf54x_kpad_device,
#endif
+#if defined(CONFIG_JOYSTICK_BFIN_ROTARY) || defined(CONFIG_JOYSTICK_BFIN_ROTARY_MODULE)
+ &bfin_rotary_device,
+#endif
+
#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
&i2c_bfin_twi0_device,
#if !defined(CONFIG_BF542)
diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
index 4d5cfeacb12..051b05c8802 100644
--- a/arch/blackfin/mach-bf548/head.S
+++ b/arch/blackfin/mach-bf548/head.S
@@ -73,25 +73,19 @@ ENTRY(_start_dma_code)
w[p0] = r0.l;
ssync;
-#if defined(CONFIG_BF54x)
+ /* enable self refresh via SRREQ */
P2.H = hi(EBIU_RSTCTL);
P2.L = lo(EBIU_RSTCTL);
R0 = [P2];
BITSET (R0, 3);
-#else
- P2.H = hi(EBIU_SDGCTL);
- P2.L = lo(EBIU_SDGCTL);
- R0 = [P2];
- BITSET (R0, 24);
-#endif
[P2] = R0;
SSYNC;
-#if defined(CONFIG_BF54x)
+
+ /* wait for SRACK bit to be set */
.LSRR_MODE:
R0 = [P2];
CC = BITTST(R0, 4);
if !CC JUMP .LSRR_MODE;
-#endif
r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
r0 = r0 << 9; /* Shift it over, */
@@ -100,6 +94,9 @@ ENTRY(_start_dma_code)
r1 = PLL_BYPASS; /* Bypass the PLL? */
r1 = r1 << 8; /* Shift it over */
r0 = r1 | r0; /* add them all together */
+#ifdef ANOMALY_05000265
+ r0 = BITSET(r0, 15); /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
p0.h = hi(PLL_CTL);
p0.l = lo(PLL_CTL); /* Load the address */
@@ -123,7 +120,7 @@ ENTRY(_start_dma_code)
w[p0] = r0.l;
ssync;
-#if defined(CONFIG_BF54x)
+ /* disable self refresh by clearing SRREQ */
P2.H = hi(EBIU_RSTCTL);
P2.L = lo(EBIU_RSTCTL);
R0 = [P2];
@@ -155,41 +152,6 @@ ENTRY(_start_dma_code)
r0.h = hi(mem_DDRCTL2);
[p0] = r0;
ssync;
-#else
- p0.l = lo(EBIU_SDRRC);
- p0.h = hi(EBIU_SDRRC);
- r0 = mem_SDRRC;
- w[p0] = r0.l;
- ssync;
-
- p0.l = LO(EBIU_SDBCTL);
- p0.h = HI(EBIU_SDBCTL); /* SDRAM Memory Bank Control Register */
- r0 = mem_SDBCTL;
- w[p0] = r0.l;
- ssync;
-
- P2.H = hi(EBIU_SDGCTL);
- P2.L = lo(EBIU_SDGCTL);
- R0 = [P2];
- BITCLR (R0, 24);
- p0.h = hi(EBIU_SDSTAT);
- p0.l = lo(EBIU_SDSTAT);
- r2.l = w[p0];
- cc = bittst(r2,3);
- if !cc jump .Lskip;
- NOP;
- BITSET (R0, 23);
-.Lskip:
- [P2] = R0;
- SSYNC;
-
- R0.L = lo(mem_SDGCTL);
- R0.H = hi(mem_SDGCTL);
- R1 = [p2];
- R1 = R1 | R0;
- [P2] = R1;
- SSYNC;
-#endif
RTS;
ENDPROC(_start_dma_code)
diff --git a/arch/blackfin/mach-bf548/include/mach/anomaly.h b/arch/blackfin/mach-bf548/include/mach/anomaly.h
index 3ad59655881..816b09278f6 100644
--- a/arch/blackfin/mach-bf548/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf548/include/mach/anomaly.h
@@ -2,18 +2,18 @@
* File: include/asm-blackfin/mach-bf548/anomaly.h
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
- * Copyright (C) 2004-2007 Analog Devices Inc.
+ * Copyright (C) 2004-2008 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
/* This file shoule be up to date with:
- * - Revision E, 11/28/2007; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
+ * - Revision G, 08/07/2008; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
#define _MACH_ANOMALY_H_
-/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
+/* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported */
#define ANOMALY_05000074 (1)
/* DMA_RUN Bit Is Not Valid after a Peripheral Receive Channel DMA Stops */
#define ANOMALY_05000119 (1)
@@ -36,14 +36,14 @@
/* TWI Slave Boot Mode Is Not Functional */
#define ANOMALY_05000324 (__SILICON_REVISION__ < 1)
/* External FIFO Boot Mode Is Not Functional */
-#define ANOMALY_05000325 (__SILICON_REVISION__ < 1)
+#define ANOMALY_05000325 (__SILICON_REVISION__ < 2)
/* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */
#define ANOMALY_05000327 (__SILICON_REVISION__ < 1)
/* Incorrect Access of OTP_STATUS During otp_write() Function */
#define ANOMALY_05000328 (__SILICON_REVISION__ < 1)
/* Synchronous Burst Flash Boot Mode Is Not Functional */
#define ANOMALY_05000329 (__SILICON_REVISION__ < 1)
-/* Host DMA Boot Mode Is Not Functional */
+/* Host DMA Boot Modes Are Not Functional */
#define ANOMALY_05000330 (__SILICON_REVISION__ < 1)
/* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */
#define ANOMALY_05000334 (__SILICON_REVISION__ < 1)
@@ -61,26 +61,102 @@
#define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
/* USB Calibration Value Is Not Intialized */
#define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
-/* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */
+/* USB Calibration Value to use */
+#define ANOMALY_05000346_value 0x5411
+/* Preboot Routine Incorrectly Alters Reset Value of USB Register */
#define ANOMALY_05000347 (__SILICON_REVISION__ < 1)
/* Data Lost when Core Reads SDH Data FIFO */
#define ANOMALY_05000349 (__SILICON_REVISION__ < 1)
/* PLL Status Register Is Inaccurate */
#define ANOMALY_05000351 (__SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Function Performs Improper System Reset */
+#define ANOMALY_05000353 (__SILICON_REVISION__ < 2)
+/* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
+#define ANOMALY_05000355 (__SILICON_REVISION__ < 1)
+/* System Stalled During A Core Access To AMC While A Core Access To NFC FIFO Is Required */
+#define ANOMALY_05000356 (__SILICON_REVISION__ < 1)
/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
#define ANOMALY_05000357 (1)
/* External Memory Read Access Hangs Core With PLL Bypass */
#define ANOMALY_05000360 (1)
/* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
#define ANOMALY_05000365 (1)
+/* WURESET Bit In SYSCR Register Does Not Properly Indicate Hibernate Wake-Up */
+#define ANOMALY_05000367 (__SILICON_REVISION__ < 1)
/* Addressing Conflict between Boot ROM and Asynchronous Memory */
#define ANOMALY_05000369 (1)
+/* Default PLL MSEL and SSEL Settings Can Cause 400MHz Product To Violate Specifications */
+#define ANOMALY_05000370 (__SILICON_REVISION__ < 1)
/* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
-#define ANOMALY_05000371 (1)
+#define ANOMALY_05000371 (__SILICON_REVISION__ < 2)
+/* USB DP/DM Data Pins May Lose State When Entering Hibernate */
+#define ANOMALY_05000372 (__SILICON_REVISION__ < 1)
/* Mobile DDR Operation Not Functional */
#define ANOMALY_05000377 (1)
/* Security/Authentication Speedpath Causes Authentication To Fail To Initiate */
-#define ANOMALY_05000378 (1)
+#define ANOMALY_05000378 (__SILICON_REVISION__ < 2)
+/* 16-Bit NAND FLASH Boot Mode Is Not Functional */
+#define ANOMALY_05000379 (1)
+/* 8-Bit NAND Flash Boot Mode Not Functional */
+#define ANOMALY_05000382 (__SILICON_REVISION__ < 1)
+/* Some ATAPI Modes Are Not Functional */
+#define ANOMALY_05000383 (1)
+/* Boot from OTP Memory Not Functional */
+#define ANOMALY_05000385 (__SILICON_REVISION__ < 1)
+/* bfrom_SysControl() Firmware Routine Not Functional */
+#define ANOMALY_05000386 (__SILICON_REVISION__ < 1)
+/* Programmable Preboot Settings Not Functional */
+#define ANOMALY_05000387 (__SILICON_REVISION__ < 1)
+/* CRC32 Checksum Support Not Functional */
+#define ANOMALY_05000388 (__SILICON_REVISION__ < 1)
+/* Reset Vector Must Not Be in SDRAM Memory Space */
+#define ANOMALY_05000389 (__SILICON_REVISION__ < 1)
+/* Changed Meaning of BCODE Field in SYSCR Register */
+#define ANOMALY_05000390 (__SILICON_REVISION__ < 1)
+/* Repeated Boot from Page-Mode or Burst-Mode Flash Memory May Fail */
+#define ANOMALY_05000391 (__SILICON_REVISION__ < 1)
+/* pTempCurrent Not Present in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000392 (__SILICON_REVISION__ < 1)
+/* Deprecated Value of dTempByteCount in ADI_BOOT_DATA Structure */
+#define ANOMALY_05000393 (__SILICON_REVISION__ < 1)
+/* Log Buffer Not Functional */
+#define ANOMALY_05000394 (__SILICON_REVISION__ < 1)
+/* Hook Routine Not Functional */
+#define ANOMALY_05000395 (__SILICON_REVISION__ < 1)
+/* Header Indirect Bit Not Functional */
+#define ANOMALY_05000396 (__SILICON_REVISION__ < 1)
+/* BK_ONES, BK_ZEROS, and BK_DATECODE Constants Not Functional */
+#define ANOMALY_05000397 (__SILICON_REVISION__ < 1)
+/* Lockbox SESR Disallows Certain User Interrupts */
+#define ANOMALY_05000404 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Does Not Save/Restore Full Context */
+#define ANOMALY_05000405 (1)
+/* Lockbox SESR Argument Checking Does Not Check L2 Memory Protection Range */
+#define ANOMALY_05000406 (__SILICON_REVISION__ < 2)
+/* Lockbox SESR Firmware Arguments Are Not Retained After First Initialization */
+#define ANOMALY_05000407 (__SILICON_REVISION__ < 2)
+/* Lockbox Firmware Memory Cleanup Routine Does not Clear Registers */
+#define ANOMALY_05000408 (1)
+/* Lockbox firmware leaves MDMA0 channel enabled */
+#define ANOMALY_05000409 (__SILICON_REVISION__ < 2)
+/* bfrom_SysControl() Firmware Function Cannot be Used to Enter Power Saving Modes */
+#define ANOMALY_05000411 (__SILICON_REVISION__ < 2)
+/* NAND Boot Mode Not Compatible With Some NAND Flash Devices */
+#define ANOMALY_05000413 (__SILICON_REVISION__ < 2)
+/* OTP_CHECK_FOR_PREV_WRITE Bit is Not Functional in bfrom_OtpWrite() API */
+#define ANOMALY_05000414 (__SILICON_REVISION__ < 2)
+/* Speculative Fetches Can Cause Undesired External FIFO Operations */
+#define ANOMALY_05000416 (1)
+/* Multichannel SPORT Channel Misalignment Under Specific Configuration */
+#define ANOMALY_05000425 (1)
+/* Speculative Fetches of Indirect-Pointer Instructions Can Cause Spurious Hardware Errors */
+#define ANOMALY_05000426 (1)
+/* CORE_EPPI_PRIO bit and SYS_EPPI_PRIO bit in the HMDMA1_CONTROL register are not functional */
+#define ANOMALY_05000427 (__SILICON_REVISION__ < 2)
+/* WB_EDGE Bit in NFC_IRQSTAT Incorrectly Behaves as a Buffer Status Bit Instead of an IRQ Status Bit */
+#define ANOMALY_05000429 (__SILICON_REVISION__ < 2)
+/* Software System Reset Corrupts PLL_LOCKCNT Register */
+#define ANOMALY_05000430 (__SILICON_REVISION__ >= 2)
/* Anomalies that don't exist on this proc */
#define ANOMALY_05000125 (0)
@@ -93,6 +169,7 @@
#define ANOMALY_05000263 (0)
#define ANOMALY_05000266 (0)
#define ANOMALY_05000273 (0)
+#define ANOMALY_05000307 (0)
#define ANOMALY_05000311 (0)
#define ANOMALY_05000323 (0)
#define ANOMALY_05000363 (0)
diff --git a/arch/blackfin/mach-bf548/include/mach/bf548.h b/arch/blackfin/mach-bf548/include/mach/bf548.h
index e748588e893..49f9b403d45 100644
--- a/arch/blackfin/mach-bf548/include/mach/bf548.h
+++ b/arch/blackfin/mach-bf548/include/mach/bf548.h
@@ -30,8 +30,6 @@
#ifndef __MACH_BF548_H__
#define __MACH_BF548_H__
-#define SUPPORTED_REVID 0
-
#define OFFSET_(x) ((x) & 0x0000FFFF)
/*some misc defines*/
@@ -108,20 +106,23 @@
#if defined(CONFIG_BF542)
# define CPU "BF542"
-# define CPUID 0x027c8000
+# define CPUID 0x27de
#elif defined(CONFIG_BF544)
-# define CPU "BF544"
-# define CPUID 0x027c8000
+# define CPU "BF544"
+# define CPUID 0x27de
#elif defined(CONFIG_BF547)
-# define CPU "BF547"
+# define CPU "BF547"
+# define CPUID 0x27de
#elif defined(CONFIG_BF548)
-# define CPU "BF548"
-# define CPUID 0x027c6000
+# define CPU "BF548"
+# define CPUID 0x27de
#elif defined(CONFIG_BF549)
-# define CPU "BF549"
-#else
-# define CPU "UNKNOWN"
-# define CPUID 0x0
+# define CPU "BF549"
+# define CPUID 0x27de
+#endif
+
+#ifndef CPU
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
#endif
#endif /* __MACH_BF48_H__ */
diff --git a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
index 5e29446a8e0..e4cf35e7ab9 100644
--- a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
@@ -82,6 +82,9 @@
# define CONFIG_UART1_RTS_PIN -1
# endif
#endif
+
+#define BFIN_UART_TX_FIFO_SIZE 2
+
/*
* The pin configuration is different from schematic
*/
@@ -105,7 +108,6 @@ struct bfin_serial_port {
#endif
};
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
struct bfin_serial_res {
unsigned long uart_base_addr;
int uart_irq;
@@ -170,8 +172,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
#endif
};
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
#define DRIVER_NAME "bfin-uart"
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
diff --git a/arch/blackfin/mach-bf548/include/mach/mem_map.h b/arch/blackfin/mach-bf548/include/mach/mem_map.h
index f99f47bc3a0..a2228428dc0 100644
--- a/arch/blackfin/mach-bf548/include/mach/mem_map.h
+++ b/arch/blackfin/mach-bf548/include/mach/mem_map.h
@@ -94,13 +94,13 @@
#endif /*CONFIG_BFIN_DCACHE*/
/* Level 2 Memory */
-#if !defined(CONFIG_BF542)
-# define L2_START 0xFEB00000
-# if defined(CONFIG_BF544)
-# define L2_LENGTH 0x10000
-# else
-# define L2_LENGTH 0x20000
-# endif
+#define L2_START 0xFEB00000
+#if defined(CONFIG_BF542)
+# define L2_LENGTH 0
+#elif defined(CONFIG_BF544)
+# define L2_LENGTH 0x10000
+#else
+# define L2_LENGTH 0x20000
#endif
/* Scratch Pad Memory */
diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S
index 75ea6a90582..0b28137b3de 100644
--- a/arch/blackfin/mach-bf561/head.S
+++ b/arch/blackfin/mach-bf561/head.S
@@ -77,6 +77,9 @@ ENTRY(_start_dma_code)
r1 = PLL_BYPASS; /* Bypass the PLL? */
r1 = r1 << 8; /* Shift it over */
r0 = r1 | r0; /* add them all together */
+#ifdef ANOMALY_05000265
+ r0 = BITSET(r0, 15); /* Add 250 mV of hysteresis to SPORT input pins */
+#endif
p0.h = hi(PLL_CTL);
p0.l = lo(PLL_CTL); /* Load the address */
diff --git a/arch/blackfin/mach-bf561/include/mach/anomaly.h b/arch/blackfin/mach-bf561/include/mach/anomaly.h
index 5c5d7d7d695..22990df04ae 100644
--- a/arch/blackfin/mach-bf561/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf561/include/mach/anomaly.h
@@ -270,5 +270,7 @@
#define ANOMALY_05000183 (0)
#define ANOMALY_05000273 (0)
#define ANOMALY_05000311 (0)
+#define ANOMALY_05000353 (1)
+#define ANOMALY_05000386 (1)
#endif
diff --git a/arch/blackfin/mach-bf561/include/mach/bf561.h b/arch/blackfin/mach-bf561/include/mach/bf561.h
index 3ef9e5f3613..18b1b3a223a 100644
--- a/arch/blackfin/mach-bf561/include/mach/bf561.h
+++ b/arch/blackfin/mach-bf561/include/mach/bf561.h
@@ -30,8 +30,6 @@
#ifndef __MACH_BF561_H__
#define __MACH_BF561_H__
-#define SUPPORTED_REVID 0x3
-
#define OFFSET_(x) ((x) & 0x0000FFFF)
/*some misc defines*/
@@ -213,11 +211,11 @@
#ifdef CONFIG_BF561
#define CPU "BF561"
-#define CPUID 0x027bb000
+#define CPUID 0x27bb
#endif
+
#ifndef CPU
-#define CPU "UNKNOWN"
-#define CPUID 0x0
+#error Unknown CPU type - This kernel doesn't seem to be configured properly
#endif
#endif /* __MACH_BF561_H__ */
diff --git a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
index 8aa02780e64..f5327264357 100644
--- a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
@@ -69,6 +69,8 @@
# endif
#endif
+#define BFIN_UART_TX_FIFO_SIZE 2
+
struct bfin_serial_port {
struct uart_port port;
unsigned int old_status;
@@ -83,7 +85,7 @@ struct bfin_serial_port {
unsigned int rx_dma_channel;
struct work_struct tx_dma_workqueue;
#else
-# if ANOMALY_05000230
+# if ANOMALY_05000363
unsigned int anomaly_threshold;
# endif
#endif
@@ -111,7 +113,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
bfin_write16(uart->port.membase + OFFSET_LSR, -1);
}
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
struct bfin_serial_res {
unsigned long uart_base_addr;
int uart_irq;
@@ -142,7 +143,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
#define DRIVER_NAME "bfin-uart"
-int nr_ports = BFIN_UART_NR_PORTS;
static void bfin_serial_hw_init(struct bfin_serial_port *uart)
{
diff --git a/arch/blackfin/mach-bf561/include/mach/mem_map.h b/arch/blackfin/mach-bf561/include/mach/mem_map.h
index c26d8486cc4..f1d4c0637bd 100644
--- a/arch/blackfin/mach-bf561/include/mach/mem_map.h
+++ b/arch/blackfin/mach-bf561/include/mach/mem_map.h
@@ -35,9 +35,16 @@
/* Memory Map for ADSP-BF561 processors */
#ifdef CONFIG_BF561
-#define L1_CODE_START 0xFFA00000
-#define L1_DATA_A_START 0xFF800000
-#define L1_DATA_B_START 0xFF900000
+#define COREA_L1_CODE_START 0xFFA00000
+#define COREA_L1_DATA_A_START 0xFF800000
+#define COREA_L1_DATA_B_START 0xFF900000
+#define COREB_L1_CODE_START 0xFF600000
+#define COREB_L1_DATA_A_START 0xFF400000
+#define COREB_L1_DATA_B_START 0xFF500000
+
+#define L1_CODE_START COREA_L1_CODE_START
+#define L1_DATA_A_START COREA_L1_DATA_A_START
+#define L1_DATA_B_START COREA_L1_DATA_B_START
#define L1_CODE_LENGTH 0x4000
@@ -72,7 +79,10 @@
/* Scratch Pad Memory */
-#define L1_SCRATCH_START 0xFFB00000
+#define COREA_L1_SCRATCH_START 0xFFB00000
+#define COREB_L1_SCRATCH_START 0xFF700000
+
+#define L1_SCRATCH_START COREA_L1_SCRATCH_START
#define L1_SCRATCH_LENGTH 0x1000
#endif /* _MEM_MAP_533_H_ */
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 847c172a99e..c13fa8da28c 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -129,6 +129,18 @@ ENTRY(_ex_icplb_miss)
#else
call __cplb_hdr;
#endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* While we were processing this, did we double fault? */
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+ r6.l = lo(SEQSTAT_EXCAUSE);
+ r6.h = hi(SEQSTAT_EXCAUSE);
+ r7 = r7 & r6;
+ r6 = 0x25;
+ CC = R7 == R6;
+ if CC JUMP _double_fault;
+#endif
+
DEBUG_HWTRACE_RESTORE(p5, r7)
RESTORE_ALL_SYS
SP = EX_SCRATCH_REG;
@@ -136,11 +148,8 @@ ENTRY(_ex_icplb_miss)
ENDPROC(_ex_icplb_miss)
ENTRY(_ex_syscall)
- (R7:6,P5:4) = [sp++];
- ASTAT = [sp++];
raise 15; /* invoked by TRAP #0, for sys call */
- sp = EX_SCRATCH_REG;
- rtx
+ jump.s _bfin_return_from_exception;
ENDPROC(_ex_syscall)
ENTRY(_ex_soft_bp)
@@ -181,8 +190,8 @@ ENTRY(_ex_single_step)
if cc jump .Lfind_priority_done;
jump.s .Lfind_priority_start;
.Lfind_priority_done:
- p4.l = _debugger_step;
- p4.h = _debugger_step;
+ p4.l = _kgdb_single_step;
+ p4.h = _kgdb_single_step;
r6 = [p4];
cc = r6 == 0;
if cc jump .Ldo_single_step;
@@ -250,6 +259,29 @@ ENTRY(_bfin_return_from_exception)
R7=LC1;
LC1=R7;
#endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* While we were processing the current exception,
+ * did we cause another, and double fault?
+ */
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+ r6.l = lo(SEQSTAT_EXCAUSE);
+ r6.h = hi(SEQSTAT_EXCAUSE);
+ r7 = r7 & r6;
+ r6 = 0x25;
+ CC = R7 == R6;
+ if CC JUMP _double_fault;
+
+ /* Did we cause a HW error? */
+ p5.l = lo(ILAT);
+ p5.h = hi(ILAT);
+ r6 = [p5];
+ r7 = 0x20; /* Did I just cause anther HW error? */
+ r7 = r7 & r1;
+ CC = R7 == R6;
+ if CC JUMP _double_fault;
+#endif
+
(R7:6,P5:4) = [sp++];
ASTAT = [sp++];
sp = EX_SCRATCH_REG;
@@ -292,6 +324,14 @@ ENTRY(_ex_trap_c)
[p4] = p5;
csync;
+#ifndef CONFIG_DEBUG_DOUBLEFAULT
+ /*
+ * Save these registers, as they are only valid in exception context
+ * (where we are now - as soon as we defer to IRQ5, they can change)
+ * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+ * but they are not very interesting, so don't save them
+ */
+
p4.l = lo(DCPLB_FAULT_ADDR);
p4.h = hi(DCPLB_FAULT_ADDR);
r7 = [p4];
@@ -304,12 +344,11 @@ ENTRY(_ex_trap_c)
p5.l = _saved_icplb_fault_addr;
[p5] = r7;
- p4.l = _excpt_saved_stuff;
- p4.h = _excpt_saved_stuff;
-
r6 = retx;
+ p4.l = _saved_retx;
+ p4.h = _saved_retx;
[p4] = r6;
-
+#endif
r6 = SYSCFG;
[p4 + 4] = r6;
BITCLR(r6, 0);
@@ -327,59 +366,56 @@ ENTRY(_ex_trap_c)
r6 = 0x3f;
sti r6;
- (R7:6,P5:4) = [sp++];
- ASTAT = [sp++];
- SP = EX_SCRATCH_REG;
raise 5;
- rtx;
+ jump.s _bfin_return_from_exception;
ENDPROC(_ex_trap_c)
/* We just realized we got an exception, while we were processing a different
* exception. This is a unrecoverable event, so crash
*/
ENTRY(_double_fault)
- /* Turn caches & protection off, to ensure we don't get any more
- * double exceptions
- */
-
- P4.L = LO(IMEM_CONTROL);
- P4.H = HI(IMEM_CONTROL);
-
- R5 = [P4]; /* Control Register*/
- BITCLR(R5,ENICPLB_P);
- SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
- .align 8;
- [P4] = R5;
- SSYNC;
-
- P4.L = LO(DMEM_CONTROL);
- P4.H = HI(DMEM_CONTROL);
- R5 = [P4];
- BITCLR(R5,ENDCPLB_P);
- SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
- .align 8;
- [P4] = R5;
- SSYNC;
-
- /* Fix up the stack */
- (R7:6,P5:4) = [sp++];
- ASTAT = [sp++];
- SP = EX_SCRATCH_REG;
-
- /* We should be out of the exception stack, and back down into
- * kernel or user space stack
- */
- SAVE_ALL_SYS
+ /* Turn caches & protection off, to ensure we don't get any more
+ * double exceptions
+ */
+
+ P4.L = LO(IMEM_CONTROL);
+ P4.H = HI(IMEM_CONTROL);
+
+ R5 = [P4]; /* Control Register*/
+ BITCLR(R5,ENICPLB_P);
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+
+ P4.L = LO(DMEM_CONTROL);
+ P4.H = HI(DMEM_CONTROL);
+ R5 = [P4];
+ BITCLR(R5,ENDCPLB_P);
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+
+ /* Fix up the stack */
+ (R7:6,P5:4) = [sp++];
+ ASTAT = [sp++];
+ SP = EX_SCRATCH_REG;
+
+ /* We should be out of the exception stack, and back down into
+ * kernel or user space stack
+ */
+ SAVE_ALL_SYS
/* The dumping functions expect the return address in the RETI
* slot. */
r6 = retx;
[sp + PT_PC] = r6;
- r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
- SP += -12;
- call _double_fault_c;
- SP += 12;
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
+ SP += -12;
+ call _double_fault_c;
+ SP += 12;
.L_double_fault_panic:
JUMP .L_double_fault_panic
@@ -388,8 +424,8 @@ ENDPROC(_double_fault)
ENTRY(_exception_to_level5)
SAVE_ALL_SYS
- p4.l = _excpt_saved_stuff;
- p4.h = _excpt_saved_stuff;
+ p4.l = _saved_retx;
+ p4.h = _saved_retx;
r6 = [p4];
[sp + PT_PC] = r6;
@@ -420,6 +456,17 @@ ENTRY(_exception_to_level5)
call _trap_c;
SP += 12;
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* Grab ILAT */
+ p2.l = lo(ILAT);
+ p2.h = hi(ILAT);
+ r0 = [p2];
+ r1 = 0x20; /* Did I just cause anther HW error? */
+ r0 = r0 & r1;
+ CC = R0 == R1;
+ if CC JUMP _double_fault;
+#endif
+
call _ret_from_exception;
RESTORE_ALL_SYS
rti;
@@ -436,7 +483,48 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
/* Try to deal with syscalls quickly. */
[--sp] = ASTAT;
[--sp] = (R7:6,P5:4);
+
+#if ANOMALY_05000283 || ANOMALY_05000315
+ cc = r7 == r7;
+ p5.h = HI(CHIPID);
+ p5.l = LO(CHIPID);
+ if cc jump 1f;
+ r7.l = W[p5];
+1:
+#endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /*
+ * Save these registers, as they are only valid in exception context
+ * (where we are now - as soon as we defer to IRQ5, they can change)
+ * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+ * but they are not very interesting, so don't save them
+ */
+
+ p4.l = lo(DCPLB_FAULT_ADDR);
+ p4.h = hi(DCPLB_FAULT_ADDR);
+ r7 = [p4];
+ p5.h = _saved_dcplb_fault_addr;
+ p5.l = _saved_dcplb_fault_addr;
+ [p5] = r7;
+
+ r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
+ p5.h = _saved_icplb_fault_addr;
+ p5.l = _saved_icplb_fault_addr;
+ [p5] = r7;
+
+ p4.l = _saved_retx;
+ p4.h = _saved_retx;
+ r6 = retx;
+ [p4] = r6;
+
r7 = SEQSTAT; /* reason code is in bit 5:0 */
+ p4.l = _saved_seqstat;
+ p4.h = _saved_seqstat;
+ [p4] = r7;
+#else
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+#endif
r6.l = lo(SEQSTAT_EXCAUSE);
r6.h = hi(SEQSTAT_EXCAUSE);
r7 = r7 & r6;
@@ -616,6 +704,9 @@ ENTRY(_system_call)
rts;
ENDPROC(_system_call)
+/* Do not mark as ENTRY() to avoid error in assembler ...
+ * this symbol need not be global anyways, so ...
+ */
_sys_trace:
call _syscall_trace;
@@ -941,6 +1032,15 @@ ENTRY(_early_trap)
SAVE_ALL_SYS
trace_buffer_stop(p0,r0);
+#if ANOMALY_05000283 || ANOMALY_05000315
+ cc = r5 == r5;
+ p4.h = HI(CHIPID);
+ p4.l = LO(CHIPID);
+ if cc jump 1f;
+ r5.l = W[p4];
+1:
+#endif
+
/* Turn caches off, to ensure we don't get double exceptions */
P4.L = LO(IMEM_CONTROL);
@@ -992,7 +1092,12 @@ ENTRY(_ex_table)
*/
.long _ex_syscall /* 0x00 - User Defined - Linux Syscall */
.long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */
+#ifdef CONFIG_KGDB
+ .long _ex_trap_c /* 0x02 - User Defined - KGDB initial connection
+ and break signal trap */
+#else
.long _ex_replaceable /* 0x02 - User Defined */
+#endif
.long _ex_trap_c /* 0x03 - User Defined - userspace stack overflow */
.long _ex_trap_c /* 0x04 - User Defined - dump trace buffer */
.long _ex_replaceable /* 0x05 - User Defined */
@@ -1432,15 +1537,7 @@ ENTRY(_sys_call_table)
.rept NR_syscalls-(.-_sys_call_table)/4
.long _sys_ni_syscall
.endr
-
- /*
- * Used to save the real RETX, IMASK and SYSCFG when temporarily
- * storing safe values across the transition from exception to IRQ5.
- */
-_excpt_saved_stuff:
- .long 0;
- .long 0;
- .long 0;
+END(_sys_call_table)
_exception_stack:
.rept 1024
diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S
index 191b4e974c4..3069df58072 100644
--- a/arch/blackfin/mach-common/head.S
+++ b/arch/blackfin/mach-common/head.S
@@ -68,6 +68,16 @@ ENTRY(__start)
M2 = r0;
M3 = r0;
+ /*
+ * Clear ITEST_COMMAND and DTEST_COMMAND registers,
+ * Leaving these as non-zero can confuse the emulator
+ */
+ p0.L = LO(DTEST_COMMAND);
+ p0.H = HI(DTEST_COMMAND);
+ [p0] = R0;
+ [p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0;
+ CSYNC;
+
trace_buffer_init(p0,r0);
P0 = R1;
R0 = R1;
@@ -90,12 +100,46 @@ ENTRY(__start)
[p0] = R0;
SSYNC;
- /* Save RETX, in case of doublefault */
- p0.l = ___retx;
- p0.h = ___retx;
+ /* in case of double faults, save a few things */
+ p0.l = _init_retx;
+ p0.h = _init_retx;
R0 = RETX;
[P0] = R0;
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* Only save these if we are storing them,
+ * This happens here, since L1 gets clobbered
+ * below
+ */
+ p0.l = _saved_retx;
+ p0.h = _saved_retx;
+ p1.l = _init_saved_retx;
+ p1.h = _init_saved_retx;
+ r0 = [p0];
+ [p1] = r0;
+
+ p0.l = _saved_dcplb_fault_addr;
+ p0.h = _saved_dcplb_fault_addr;
+ p1.l = _init_saved_dcplb_fault_addr;
+ p1.h = _init_saved_dcplb_fault_addr;
+ r0 = [p0];
+ [p1] = r0;
+
+ p0.l = _saved_icplb_fault_addr;
+ p0.h = _saved_icplb_fault_addr;
+ p1.l = _init_saved_icplb_fault_addr;
+ p1.h = _init_saved_icplb_fault_addr;
+ r0 = [p0];
+ [p1] = r0;
+
+ p0.l = _saved_seqstat;
+ p0.h = _saved_seqstat;
+ p1.l = _init_saved_seqstat;
+ p1.h = _init_saved_seqstat;
+ r0 = [p0];
+ [p1] = r0;
+#endif
+
/* Initialize stack pointer */
sp.l = lo(INITIAL_STACK);
sp.h = hi(INITIAL_STACK);
@@ -107,7 +151,7 @@ ENTRY(__start)
#endif
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
- call _bf53x_relocate_l1_mem;
+ call _bfin_relocate_l1_mem;
#ifdef CONFIG_BFIN_KERNEL_CLOCK
call _start_dma_code;
#endif
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index b27e59d3240..4a2ec7a9675 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -143,7 +143,7 @@ ENTRY(_evt_ivhw)
fp = 0;
#endif
-#if ANOMALY_05000283
+#if ANOMALY_05000283 || ANOMALY_05000315
cc = r7 == r7;
p5.h = HI(CHIPID);
p5.l = LO(CHIPID);
@@ -179,7 +179,16 @@ ENTRY(_evt_ivhw)
call _trap_c;
SP += 12;
+#ifdef EBIU_ERRMST
+ /* make sure EBIU_ERRMST is clear */
+ p0.l = LO(EBIU_ERRMST);
+ p0.h = HI(EBIU_ERRMST);
+ r0.l = (CORE_ERROR | CORE_MERROR);
+ w[p0] = r0.l;
+#endif
+
call _ret_from_exception;
+
.Lcommon_restore_all_sys:
RESTORE_ALL_SYS
rti;
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index 5fa536727c6..34e8a726ffd 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -243,12 +243,14 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
#endif
static struct irq_chip bfin_core_irqchip = {
+ .name = "CORE",
.ack = bfin_ack_noop,
.mask = bfin_core_mask_irq,
.unmask = bfin_core_unmask_irq,
};
static struct irq_chip bfin_internal_irqchip = {
+ .name = "INTN",
.ack = bfin_ack_noop,
.mask = bfin_internal_mask_irq,
.unmask = bfin_internal_unmask_irq,
@@ -278,6 +280,7 @@ static void bfin_generic_error_unmask_irq(unsigned int irq)
}
static struct irq_chip bfin_generic_error_irqchip = {
+ .name = "ERROR",
.ack = bfin_ack_noop,
.mask_ack = bfin_generic_error_mask_irq,
.mask = bfin_generic_error_mask_irq,
@@ -361,6 +364,14 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
}
#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
+static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
+{
+ struct irq_desc *desc = irq_desc + irq;
+ /* May not call generic set_irq_handler() due to spinlock
+ recursion. */
+ desc->handle_irq = handle;
+}
+
#if !defined(CONFIG_BF54x)
static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
@@ -473,9 +484,9 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
SSYNC();
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
- set_irq_handler(irq, handle_edge_irq);
+ bfin_set_irq_handler(irq, handle_edge_irq);
else
- set_irq_handler(irq, handle_level_irq);
+ bfin_set_irq_handler(irq, handle_level_irq);
return 0;
}
@@ -495,6 +506,7 @@ int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
#endif
static struct irq_chip bfin_gpio_irqchip = {
+ .name = "GPIO",
.ack = bfin_gpio_ack_irq,
.mask = bfin_gpio_mask_irq,
.mask_ack = bfin_gpio_mask_ack_irq,
@@ -804,10 +816,10 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
pint[bank]->edge_set = pintbit;
- set_irq_handler(irq, handle_edge_irq);
+ bfin_set_irq_handler(irq, handle_edge_irq);
} else {
pint[bank]->edge_clear = pintbit;
- set_irq_handler(irq, handle_level_irq);
+ bfin_set_irq_handler(irq, handle_level_irq);
}
SSYNC();
@@ -884,6 +896,7 @@ void bfin_pm_restore(void)
#endif
static struct irq_chip bfin_gpio_irqchip = {
+ .name = "GPIO",
.ack = bfin_gpio_ack_irq,
.mask = bfin_gpio_mask_irq,
.mask_ack = bfin_gpio_mask_ack_irq,
@@ -1136,8 +1149,4 @@ void do_irq(int vec, struct pt_regs *fp)
vec = ivg->irqno;
}
asm_do_IRQ(vec, fp);
-
-#ifdef CONFIG_KGDB
- kgdb_process_breakpoint();
-#endif
}
diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile
index 2a7202ce01f..d489f894f4b 100644
--- a/arch/blackfin/mm/Makefile
+++ b/arch/blackfin/mm/Makefile
@@ -2,4 +2,4 @@
# arch/blackfin/mm/Makefile
#
-obj-y := blackfin_sram.o init.o
+obj-y := sram-alloc.o isram-driver.o init.o
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c
new file mode 100644
index 00000000000..22913e7a181
--- /dev/null
+++ b/arch/blackfin/mm/isram-driver.c
@@ -0,0 +1,201 @@
+/*
+ * Description: Instruction SRAM accessor functions for the Blackfin
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <asm/blackfin.h>
+
+/*
+ * IMPORTANT WARNING ABOUT THESE FUNCTIONS
+ *
+ * The emulator will not function correctly if a write command is left in
+ * ITEST_COMMAND or DTEST_COMMAND AND access to cache memory is needed by
+ * the emulator. To avoid such problems, ensure that both ITEST_COMMAND
+ * and DTEST_COMMAND are zero when exiting these functions.
+ */
+
+
+/*
+ * On the Blackfin, L1 instruction sram (which operates at core speeds) can not
+ * be accessed by a normal core load, so we need to go through a few hoops to
+ * read/write it.
+ * To try to make it easier - we export a memcpy interface, where either src or
+ * dest can be in this special L1 memory area.
+ * The low level read/write functions should not be exposed to the rest of the
+ * kernel, since they operate on 64-bit data, and need specific address alignment
+ */
+
+static DEFINE_SPINLOCK(dtest_lock);
+
+/* Takes a void pointer */
+#define IADDR2DTEST(x) \
+ ({ unsigned long __addr = (unsigned long)(x); \
+ (__addr & 0x47F8) | /* address bits 14 & 10:3 */ \
+ (__addr & 0x0800) << 15 | /* address bit 11 */ \
+ (__addr & 0x3000) << 4 | /* address bits 13:12 */ \
+ (__addr & 0x8000) << 8 | /* address bit 15 */ \
+ (0x1000004); /* isram access */ \
+ })
+
+/* Takes a pointer, and returns the offset (in bits) which things should be shifted */
+#define ADDR2OFFSET(x) ((((unsigned long)(x)) & 0x7) * 8)
+
+/* Takes a pointer, determines if it is the last byte in the isram 64-bit data type */
+#define ADDR2LAST(x) ((((unsigned long)x) & 0x7) == 0x7)
+
+static void isram_write(const void *addr, uint64_t data)
+{
+ uint32_t cmd;
+ unsigned long flags;
+
+ if (addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH))
+ return;
+
+ cmd = IADDR2DTEST(addr) | 1; /* write */
+
+ /*
+ * Writes to DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+ * While in exception context - atomicity is guaranteed or double fault
+ */
+ spin_lock_irqsave(&dtest_lock, flags);
+
+ bfin_write_DTEST_DATA0(data & 0xFFFFFFFF);
+ bfin_write_DTEST_DATA1(data >> 32);
+
+ /* use the builtin, since interrupts are already turned off */
+ __builtin_bfin_csync();
+ bfin_write_DTEST_COMMAND(cmd);
+ __builtin_bfin_csync();
+
+ bfin_write_DTEST_COMMAND(0);
+ __builtin_bfin_csync();
+
+ spin_unlock_irqrestore(&dtest_lock, flags);
+}
+
+static uint64_t isram_read(const void *addr)
+{
+ uint32_t cmd;
+ unsigned long flags;
+ uint64_t ret;
+
+ if (addr > (void *)(L1_CODE_START + L1_CODE_LENGTH))
+ return 0;
+
+ cmd = IADDR2DTEST(addr) | 0; /* read */
+
+ /*
+ * Reads of DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND
+ * While in exception context - atomicity is guaranteed or double fault
+ */
+ spin_lock_irqsave(&dtest_lock, flags);
+ /* use the builtin, since interrupts are already turned off */
+ __builtin_bfin_csync();
+ bfin_write_DTEST_COMMAND(cmd);
+ __builtin_bfin_csync();
+ ret = bfin_read_DTEST_DATA0() | ((uint64_t)bfin_read_DTEST_DATA1() << 32);
+
+ bfin_write_DTEST_COMMAND(0);
+ __builtin_bfin_csync();
+ spin_unlock_irqrestore(&dtest_lock, flags);
+
+ return ret;
+}
+
+static bool isram_check_addr(const void *addr, size_t n)
+{
+ if ((addr >= (void *)L1_CODE_START) &&
+ (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) {
+ if ((addr + n) >= (void *)(L1_CODE_START + L1_CODE_LENGTH)) {
+ show_stack(NULL, NULL);
+ printk(KERN_ERR "isram_memcpy: copy involving %p length "
+ "(%zu) too long\n", addr, n);
+ }
+ return true;
+ }
+ return false;
+}
+
+/*
+ * The isram_memcpy() function copies n bytes from memory area src to memory area dest.
+ * The isram_memcpy() function returns a pointer to dest.
+ * Either dest or src can be in L1 instruction sram.
+ */
+void *isram_memcpy(void *dest, const void *src, size_t n)
+{
+ uint64_t data_in = 0, data_out = 0;
+ size_t count;
+ bool dest_in_l1, src_in_l1, need_data, put_data;
+ unsigned char byte, *src_byte, *dest_byte;
+
+ src_byte = (unsigned char *)src;
+ dest_byte = (unsigned char *)dest;
+
+ dest_in_l1 = isram_check_addr(dest, n);
+ src_in_l1 = isram_check_addr(src, n);
+
+ need_data = true;
+ put_data = true;
+ for (count = 0; count < n; count++) {
+ if (src_in_l1) {
+ if (need_data) {
+ data_in = isram_read(src + count);
+ need_data = false;
+ }
+
+ if (ADDR2LAST(src + count))
+ need_data = true;
+
+ byte = (unsigned char)((data_in >> ADDR2OFFSET(src + count)) & 0xff);
+
+ } else {
+ /* src is in L2 or L3 - so just dereference*/
+ byte = src_byte[count];
+ }
+
+ if (dest_in_l1) {
+ if (put_data) {
+ data_out = isram_read(dest + count);
+ put_data = false;
+ }
+
+ data_out &= ~((uint64_t)0xff << ADDR2OFFSET(dest + count));
+ data_out |= ((uint64_t)byte << ADDR2OFFSET(dest + count));
+
+ if (ADDR2LAST(dest + count)) {
+ put_data = true;
+ isram_write(dest + count, data_out);
+ }
+ } else {
+ /* dest in L2 or L3 - so just dereference */
+ dest_byte[count] = byte;
+ }
+ }
+
+ /* make sure we dump the last byte if necessary */
+ if (dest_in_l1 && !put_data)
+ isram_write(dest + count, data_out);
+
+ return dest;
+}
+EXPORT_SYMBOL(isram_memcpy);
+
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/sram-alloc.c
index 4f5e887a0d9..0f1ca6930c1 100644
--- a/arch/blackfin/mm/blackfin_sram.c
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -1,13 +1,13 @@
/*
- * File: arch/blackfin/mm/blackfin_sram.c
+ * File: arch/blackfin/mm/sram-alloc.c
* Based on:
* Author:
*
* Created:
- * Description: SRAM driver for Blackfin ADSP-BF5xx
+ * Description: SRAM allocator for Blackfin L1 and L2 memory
*
* Modified:
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2004-2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
@@ -78,7 +78,7 @@ static void __init l1sram_init(void)
free_l1_ssram_head.next =
kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
if (!free_l1_ssram_head.next) {
- printk(KERN_INFO"Fail to initialize Scratchpad data SRAM.\n");
+ printk(KERN_INFO "Failed to initialize Scratchpad data SRAM\n");
return;
}
@@ -102,7 +102,7 @@ static void __init l1_data_sram_init(void)
free_l1_data_A_sram_head.next =
kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
if (!free_l1_data_A_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L1 Data A SRAM.\n");
+ printk(KERN_INFO "Failed to initialize L1 Data A SRAM\n");
return;
}
@@ -123,7 +123,7 @@ static void __init l1_data_sram_init(void)
free_l1_data_B_sram_head.next =
kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
if (!free_l1_data_B_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L1 Data B SRAM.\n");
+ printk(KERN_INFO "Failed to initialize L1 Data B SRAM\n");
return;
}
@@ -151,7 +151,7 @@ static void __init l1_inst_sram_init(void)
free_l1_inst_sram_head.next =
kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
if (!free_l1_inst_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L1 Instruction SRAM.\n");
+ printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
return;
}
@@ -179,7 +179,7 @@ static void __init l2_sram_init(void)
free_l2_sram_head.next =
kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
if (!free_l2_sram_head.next) {
- printk(KERN_INFO"Fail to initialize L2 SRAM.\n");
+ printk(KERN_INFO "Failed to initialize L2 SRAM\n");
return;
}
@@ -351,28 +351,31 @@ static int _sram_free(const void *addr,
int sram_free(const void *addr)
{
- if (0) {}
+
#if L1_CODE_LENGTH != 0
- else if (addr >= (void *)L1_CODE_START
+ if (addr >= (void *)L1_CODE_START
&& addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
return l1_inst_sram_free(addr);
+ else
#endif
#if L1_DATA_A_LENGTH != 0
- else if (addr >= (void *)L1_DATA_A_START
+ if (addr >= (void *)L1_DATA_A_START
&& addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
return l1_data_A_sram_free(addr);
+ else
#endif
#if L1_DATA_B_LENGTH != 0
- else if (addr >= (void *)L1_DATA_B_START
+ if (addr >= (void *)L1_DATA_B_START
&& addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
return l1_data_B_sram_free(addr);
+ else
#endif
#if L2_LENGTH != 0
- else if (addr >= (void *)L2_START
+ if (addr >= (void *)L2_START
&& addr < (void *)(L2_START + L2_LENGTH))
return l2_sram_free(addr);
-#endif
else
+#endif
return -1;
}
EXPORT_SYMBOL(sram_free);
diff --git a/arch/cris/arch-v10/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c
index 2f9bbb26d60..c8adef36416 100644
--- a/arch/cris/arch-v10/boot/tools/build.c
+++ b/arch/cris/arch-v10/boot/tools/build.c
@@ -30,7 +30,6 @@
#include <sys/sysmacros.h>
#include <unistd.h> /* contains read/write */
#include <fcntl.h>
-#include <linux/a.out.h>
#include <errno.h>
#define MINIX_HEADER 32
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 396ab059efa..107cb5bb9f3 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -66,9 +66,6 @@ config TIME_LOW_RES
bool
default y
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
config NO_IOPORT
def_bool y
diff --git a/arch/h8300/include/asm/a.out.h b/arch/h8300/include/asm/a.out.h
deleted file mode 100644
index ded780f0a49..00000000000
--- a/arch/h8300/include/asm/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __H8300_A_OUT_H__
-#define __H8300_A_OUT_H__
-
-struct exec
-{
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif /* __H8300_A_OUT_H__ */
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index dfbe7ab9ffe..a8ef654a5a0 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -34,7 +34,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/fs.h>
diff --git a/arch/ia64/include/asm/a.out.h b/arch/ia64/include/asm/a.out.h
deleted file mode 100644
index 193dcfb6759..00000000000
--- a/arch/ia64/include/asm/a.out.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _ASM_IA64_A_OUT_H
-#define _ASM_IA64_A_OUT_H
-
-/*
- * No a.out format has been (or should be) defined so this file is
- * just a dummy that allows us to get binfmt_elf compiled. It
- * probably would be better to clean up binfmt_elf.c so it does not
- * necessarily depend on there being a.out support.
- *
- * Modified 1998-2002
- * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co.
- */
-
-#include <linux/types.h>
-
-struct exec {
- unsigned long a_info;
- unsigned long a_text;
- unsigned long a_data;
- unsigned long a_bss;
- unsigned long a_entry;
-};
-
-#define N_TXTADDR(x) 0
-#define N_DATADDR(x) 0
-#define N_BSSADDR(x) 0
-#define N_DRSIZE(x) 0
-#define N_TRSIZE(x) 0
-#define N_SYMSIZE(x) 0
-#define N_TXTOFF(x) 0
-
-#endif /* _ASM_IA64_A_OUT_H */
diff --git a/arch/ia64/include/asm/siginfo.h b/arch/ia64/include/asm/siginfo.h
index 9294e4b0c8b..118d4297900 100644
--- a/arch/ia64/include/asm/siginfo.h
+++ b/arch/ia64/include/asm/siginfo.h
@@ -113,11 +113,6 @@ typedef struct siginfo {
#undef NSIGSEGV
#define NSIGSEGV 3
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
-#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */
#undef NSIGTRAP
#define NSIGTRAP 4
diff --git a/arch/ia64/include/asm/statfs.h b/arch/ia64/include/asm/statfs.h
index 811097974f3..1e589669de5 100644
--- a/arch/ia64/include/asm/statfs.h
+++ b/arch/ia64/include/asm/statfs.h
@@ -8,55 +8,13 @@
* David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
*/
-#ifndef __KERNEL_STRICT_NAMES
-# include <linux/types.h>
-typedef __kernel_fsid_t fsid_t;
-#endif
-
/*
- * This is ugly --- we're already 64-bit, so just duplicate the definitions
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the IA64 ABI will.
*/
-struct statfs {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-
-
-struct statfs64 {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
-struct compat_statfs64 {
- __u32 f_type;
- __u32 f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-} __attribute__((packed));
+#include <asm-generic/statfs.h>
#endif /* _ASM_IA64_STATFS_H */
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 200100ea761..f482a9098e3 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -21,7 +21,6 @@
#include <linux/bitops.h>
#include <linux/kexec.h>
-#include <asm/a.out.h>
#include <asm/dma.h>
#include <asm/ia32.h>
#include <asm/io.h>
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index f57113f1f89..00289c178f8 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -36,9 +36,6 @@ config NO_IOPORT
config NO_DMA
def_bool y
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
config HZ
int
default 100
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 8c5e1de68fc..41e5bf02e23 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -5,6 +5,7 @@
config M68K
bool
default y
+ select HAVE_AOUT
select HAVE_IDE
config MMU
@@ -53,9 +54,6 @@ config NO_IOPORT
config NO_DMA
def_bool SUN3
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
config HZ
int
default 100
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 2e7515e8db9..0a8998315e5 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -73,9 +73,6 @@ config GENERIC_CLOCKEVENTS
config NO_IOPORT
def_bool y
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
source "init/Kconfig"
menu "Processor type and features"
diff --git a/arch/m68knommu/include/asm/a.out.h b/arch/m68knommu/include/asm/a.out.h
deleted file mode 100644
index ce18ef99de0..00000000000
--- a/arch/m68knommu/include/asm/a.out.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-m68k/a.out.h>
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
index 47502d5ec19..3f2d7745f31 100644
--- a/arch/m68knommu/kernel/process.c
+++ b/arch/m68knommu/kernel/process.c
@@ -25,7 +25,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/fs.h>
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index 46f8f9d0c40..5d5d56bcd0e 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -22,7 +22,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/a.out.h>
#include <linux/user.h>
#include <linux/string.h>
#include <linux/linkage.h>
diff --git a/arch/mips/include/asm/a.out.h b/arch/mips/include/asm/a.out.h
deleted file mode 100644
index cad8371422a..00000000000
--- a/arch/mips/include/asm/a.out.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 - 1999, 2003 by Ralf Baechle
- */
-#ifndef _ASM_A_OUT_H
-#define _ASM_A_OUT_H
-
-#ifdef __KERNEL__
-
-
-#endif
-
-struct exec
-{
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for
- file, in bytes */
- unsigned a_syms; /* length of symbol table data in file,
- in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in
- bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif /* _ASM_A_OUT_H */
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 22fc19bbe87..ca2e4026ad2 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -22,7 +22,6 @@
#include <linux/personality.h>
#include <linux/sys.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/kallsyms.h>
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 343015a2f41..37970d9b218 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -7,7 +7,6 @@
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2001 MIPS Technologies, Inc.
*/
-#include <linux/a.out.h>
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/linkage.h>
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index e856218da90..dd557c9cf00 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -53,9 +53,6 @@ config QUICKLIST
config ARCH_HAS_ILOG2_U32
def_bool y
-config ARCH_SUPPORTS_AOUT
- def_bool n
-
# Use the generic interrupt handling code in kernel/irq/
config GENERIC_HARDIRQS
def_bool y
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index a7d4fd353c2..8313fccced5 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -76,9 +76,6 @@ config IRQ_PER_CPU
bool
default y
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
# unless you want to implement ACPI on PA-RISC ... ;-)
config PM
bool
diff --git a/arch/powerpc/include/asm/a.out.h b/arch/powerpc/include/asm/a.out.h
deleted file mode 100644
index 89cead6b176..00000000000
--- a/arch/powerpc/include/asm/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_POWERPC_A_OUT_H
-#define _ASM_POWERPC_A_OUT_H
-
-struct exec
-{
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif /* _ASM_POWERPC_A_OUT_H */
diff --git a/arch/powerpc/include/asm/siginfo.h b/arch/powerpc/include/asm/siginfo.h
index 12f1bce037b..49495b0534e 100644
--- a/arch/powerpc/include/asm/siginfo.h
+++ b/arch/powerpc/include/asm/siginfo.h
@@ -15,11 +15,6 @@
#include <asm-generic/siginfo.h>
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
-#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */
#undef NSIGTRAP
#define NSIGTRAP 4
diff --git a/arch/powerpc/include/asm/statfs.h b/arch/powerpc/include/asm/statfs.h
index 67024026c10..5244834583a 100644
--- a/arch/powerpc/include/asm/statfs.h
+++ b/arch/powerpc/include/asm/statfs.h
@@ -1,60 +1,6 @@
#ifndef _ASM_POWERPC_STATFS_H
#define _ASM_POWERPC_STATFS_H
-/* For ppc32 we just use the generic definitions, not so simple on ppc64 */
-
-#ifndef __powerpc64__
#include <asm-generic/statfs.h>
-#else
-
-#ifndef __KERNEL_STRICT_NAMES
-#include <linux/types.h>
-typedef __kernel_fsid_t fsid_t;
-#endif
-
-/*
- * We're already 64-bit, so duplicate the definition
- */
-struct statfs {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-
-struct statfs64 {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-struct compat_statfs64 {
- __u32 f_type;
- __u32 f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-};
-#endif /* ! __powerpc64__ */
#endif
diff --git a/arch/powerpc/kernel/softemu8xx.c b/arch/powerpc/kernel/softemu8xx.c
index c906c4bf683..23c8c5e7dc4 100644
--- a/arch/powerpc/kernel/softemu8xx.c
+++ b/arch/powerpc/kernel/softemu8xx.c
@@ -23,7 +23,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <asm/pgtable.h>
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 81ccb8dd1a5..f5def6cf5cd 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -23,7 +23,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 690ca7b0dcf..2c8b8091250 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -659,7 +659,7 @@ enum {
Opt_uid, Opt_gid, Opt_mode, Opt_debug, Opt_err,
};
-static match_table_t spufs_tokens = {
+static const match_table_t spufs_tokens = {
{ Opt_uid, "uid=%d" },
{ Opt_gid, "gid=%d" },
{ Opt_mode, "mode=%o" },
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 1ba7ce5aafa..272d79a8d28 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -17,7 +17,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/major.h>
#include <linux/interrupt.h>
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 364714757cf..d4c61c3c966 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -23,7 +23,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/delay.h>
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 88ccf3a08a9..82c14d203d8 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -33,7 +33,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/string.h>
#include <linux/delay.h>
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 7b01d67b4e4..ec341707e41 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -25,7 +25,6 @@
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/major.h>
#include <linux/interrupt.h>
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 7383781f3e6..36313801cd5 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -219,7 +219,7 @@ static int hypfs_release(struct inode *inode, struct file *filp)
enum { opt_uid, opt_gid, opt_err };
-static match_table_t hypfs_tokens = {
+static const match_table_t hypfs_tokens = {
{opt_uid, "uid=%u"},
{opt_gid, "gid=%u"},
{opt_err, NULL}
diff --git a/arch/s390/include/asm/statfs.h b/arch/s390/include/asm/statfs.h
index 099a4557919..06cc70307ec 100644
--- a/arch/s390/include/asm/statfs.h
+++ b/arch/s390/include/asm/statfs.h
@@ -12,19 +12,16 @@
#ifndef __s390x__
#include <asm-generic/statfs.h>
#else
+/*
+ * We can't use <asm-generic/statfs.h> because in 64-bit mode
+ * we mix ints of different sizes in our struct statfs.
+ */
#ifndef __KERNEL_STRICT_NAMES
-
#include <linux/types.h>
-
typedef __kernel_fsid_t fsid_t;
-
#endif
-/*
- * This is ugly -- we're already 64-bit clean, so just duplicate the
- * definitions.
- */
struct statfs {
int f_type;
int f_bsize;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index a214002114e..97671dac12a 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -20,6 +20,11 @@ config GENERIC_ISA_DMA
bool
default y
+config GENERIC_GPIO
+ bool
+ help
+ Generic GPIO API support
+
config ARCH_NO_VIRT_TO_BUS
def_bool y
@@ -69,6 +74,9 @@ config SPARC
select HAVE_OPROFILE
select HAVE_ARCH_KGDB if !SMP
select HAVE_ARCH_TRACEHOOK
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select RTC_CLASS
+ select RTC_DRV_M48T59
# Identify this as a Sparc32 build
config SPARC32
@@ -204,17 +212,6 @@ config SUN_PM
Enable power management and CPU standby features on supported
SPARC platforms.
-config SUN4
- bool "Support for SUN4 machines (disables SUN4[CDM] support)"
- depends on !SMP
- default n
- help
- Say Y here if, and only if, your machine is a sun4. Note that
- a kernel compiled with this option will run only on sun4.
- (And the current version will probably work only on sun4/330.)
-
-if !SUN4
-
config PCI
bool "Support for PCI and PS/2 keyboard/mouse"
help
@@ -227,11 +224,6 @@ config PCI_SYSCALL
source "drivers/pci/Kconfig"
-endif
-
-config NO_DMA
- def_bool !PCI
-
config SUN_OPENPROMFS
tristate "Openprom tree appears in /proc/openprom"
help
@@ -263,9 +255,7 @@ source "net/Kconfig"
source "drivers/Kconfig"
-if !SUN4
source "drivers/sbus/char/Kconfig"
-endif
# This one must be before the filesystem configs. -DaveM
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index a5f0ce734ff..2d2769d766e 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -15,14 +15,11 @@ header-y += signal_32.h
header-y += signal_64.h
header-y += stat_32.h
header-y += stat_64.h
-header-y += statfs_32.h
-header-y += statfs_64.h
header-y += unistd_32.h
header-y += unistd_64.h
header-y += apc.h
header-y += asi.h
-header-y += bpp.h
header-y += display7seg.h
header-y += envctrl.h
header-y += fbio.h
@@ -41,5 +38,4 @@ header-y += reg_64.h
header-y += traps.h
header-y += uctx.h
header-y += utrap.h
-header-y += vfc_ioctls.h
header-y += watchdog.h
diff --git a/arch/sparc/include/asm/asmmacro.h b/arch/sparc/include/asm/asmmacro.h
index a619a4d97aa..a995bf8aba3 100644
--- a/arch/sparc/include/asm/asmmacro.h
+++ b/arch/sparc/include/asm/asmmacro.h
@@ -34,12 +34,7 @@
/* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+
likes byte accesses. These are to avoid ifdef mania. */
-#ifdef CONFIG_SUN4
-#define lduXa lduha
-#define stXa stha
-#else
#define lduXa lduba
#define stXa stba
-#endif
#endif /* !(_SPARC_ASMMACRO_H) */
diff --git a/arch/sparc/include/asm/bpp.h b/arch/sparc/include/asm/bpp.h
deleted file mode 100644
index 31f515e499a..00000000000
--- a/arch/sparc/include/asm/bpp.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef _SPARC_BPP_H
-#define _SPARC_BPP_H
-
-/*
- * Copyright (c) 1995 Picture Elements
- * Stephen Williams
- * Gus Baldauf
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-#include <linux/ioctl.h>
-
-/*
- * This is a driver that supports IEEE Std 1284-1994 communications
- * with compliant or compatible devices. It will use whatever features
- * the device supports, prefering those that are typically faster.
- *
- * When the device is opened, it is left in COMPATIBILITY mode, and
- * writes work like any printer device. The driver only attempt to
- * negotiate 1284 modes when needed so that plugs can be pulled,
- * switch boxes switched, etc., without disrupting things. It will
- * also leave the device in compatibility mode when closed.
- */
-
-
-
-/*
- * This driver also supplies ioctls to manually manipulate the
- * pins. This is great for testing devices, or writing code to deal
- * with bizzarro-mode of the ACME Special TurboThingy Plus.
- *
- * NOTE: These ioctl currently do not interact well with
- * read/write. Caveat emptor.
- *
- * PUT_PINS allows us to assign the sense of all the pins, including
- * the data pins if being driven by the host. The GET_PINS returns the
- * pins that the peripheral drives, including data if appropriate.
- */
-
-# define BPP_PUT_PINS _IOW('B', 1, int)
-# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */
-# define BPP_PUT_DATA _IOW('B', 3, int)
-# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */
-
-/*
- * Set the data bus to input mode. Disengage the data bin driver and
- * be prepared to read values from the peripheral. If the arg is 0,
- * then revert the bus to output mode.
- */
-# define BPP_SET_INPUT _IOW('B', 5, int)
-
-/*
- * These bits apply to the PUT operation...
- */
-# define BPP_PP_nStrobe 0x0001
-# define BPP_PP_nAutoFd 0x0002
-# define BPP_PP_nInit 0x0004
-# define BPP_PP_nSelectIn 0x0008
-
-/*
- * These apply to the GET operation, which also reads the current value
- * of the previously put values. A bit mask of these will be returned
- * as a bit mask in the return code of the ioctl().
- */
-# define BPP_GP_nAck 0x0100
-# define BPP_GP_Busy 0x0200
-# define BPP_GP_PError 0x0400
-# define BPP_GP_Select 0x0800
-# define BPP_GP_nFault 0x1000
-
-#endif
diff --git a/arch/sparc/include/asm/bugs.h b/arch/sparc/include/asm/bugs.h
index e179bc12f64..61d86bbbe2b 100644
--- a/arch/sparc/include/asm/bugs.h
+++ b/arch/sparc/include/asm/bugs.h
@@ -7,10 +7,6 @@
#include <asm/cpudata.h>
#endif
-#ifdef CONFIG_SPARC64
-#include <asm/sstate.h>
-#endif
-
extern unsigned long loops_per_jiffy;
static void __init check_bugs(void)
@@ -18,7 +14,4 @@ static void __init check_bugs(void)
#if defined(CONFIG_SPARC32) && !defined(CONFIG_SMP)
cpu_data(0).udelay_val = loops_per_jiffy;
#endif
-#ifdef CONFIG_SPARC64
- sstate_running();
-#endif
}
diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h
index 532975ecfe1..7da7c13d23c 100644
--- a/arch/sparc/include/asm/cpudata_64.h
+++ b/arch/sparc/include/asm/cpudata_64.h
@@ -86,7 +86,6 @@ extern struct trap_per_cpu trap_block[NR_CPUS];
extern void init_cur_cpu_trap(struct thread_info *);
extern void setup_tba(void);
extern int ncpus_probed;
-extern void __init cpu_probe(void);
extern const struct seq_operations cpuinfo_op;
extern unsigned long real_hard_smp_processor_id(void);
diff --git a/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h
index f3a641e6b2c..8a57ea0573e 100644
--- a/arch/sparc/include/asm/dma-mapping_32.h
+++ b/arch/sparc/include/asm/dma-mapping_32.h
@@ -1,11 +1,60 @@
#ifndef _ASM_SPARC_DMA_MAPPING_H
#define _ASM_SPARC_DMA_MAPPING_H
+#include <linux/types.h>
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif /* PCI */
+struct device;
+struct scatterlist;
+struct page;
+
+#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle);
+extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size,
+ enum dma_data_direction direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+ size_t size, enum dma_data_direction direction);
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction);
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction);
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction direction);
+extern void dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction);
+extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
+extern int dma_get_cache_alignment(void);
+
+#define dma_alloc_noncoherent dma_alloc_coherent
+#define dma_free_noncoherent dma_free_coherent
#endif /* _ASM_SPARC_DMA_MAPPING_H */
diff --git a/arch/sparc/include/asm/dma.h b/arch/sparc/include/asm/dma.h
index aa1d90ac04c..b554927bbaf 100644
--- a/arch/sparc/include/asm/dma.h
+++ b/arch/sparc/include/asm/dma.h
@@ -1,8 +1,139 @@
-#ifndef ___ASM_SPARC_DMA_H
-#define ___ASM_SPARC_DMA_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/dma_64.h>
+#ifndef _ASM_SPARC_DMA_H
+#define _ASM_SPARC_DMA_H
+
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
+#define MAX_DMA_CHANNELS 8
+#define DMA_MODE_READ 1
+#define DMA_MODE_WRITE 2
+#define MAX_DMA_ADDRESS (~0UL)
+
+/* Useful constants */
+#define SIZE_16MB (16*1024*1024)
+#define SIZE_64K (64*1024)
+
+/* SBUS DMA controller reg offsets */
+#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
+#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
+#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
+#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
+#define DMA_VERS0 0x00000000 /* Sunray DMA version */
+#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
+#define DMA_VERS1 0x80000000 /* DMA rev 1 */
+#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
+#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
+#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
+#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
+#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
+#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
+#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
+#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
+#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
+#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
+#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
+#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
+#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
+#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
+#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
+#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64 0x000c0000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32 0x00040000 /* SCSI: 32byte bursts */
+#define DMA_BRST16 0x00000000 /* SCSI: 16byte bursts */
+#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
+#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
+#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
+#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
+#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1 0x01
+#define DMA_BURST2 0x02
+#define DMA_BURST4 0x04
+#define DMA_BURST8 0x08
+#define DMA_BURST16 0x10
+#define DMA_BURST32 0x20
+#define DMA_BURST64 0x40
+#define DMA_BURSTBITS 0x7f
+
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
#else
-#include <asm/dma_32.h>
+#define isa_dma_bridge_buggy (0)
#endif
+
+#ifdef CONFIG_SPARC32
+
+/* Routines for data transfer buffers. */
+BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
+BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long)
+
+#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
+#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
+
+struct page;
+struct device;
+struct scatterlist;
+
+/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
+BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, struct device *, char *, unsigned long)
+BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct device *, struct scatterlist *, int)
+BTFIXUPDEF_CALL(void, mmu_release_scsi_one, struct device *, __u32, unsigned long)
+BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct device *, struct scatterlist *, int)
+
+#define mmu_get_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_get_scsi_one)(dev,vaddr,len)
+#define mmu_get_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_get_scsi_sgl)(dev,sg,sz)
+#define mmu_release_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_release_scsi_one)(dev,vaddr,len)
+#define mmu_release_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_release_scsi_sgl)(dev,sg,sz)
+
+/*
+ * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
+ *
+ * The mmu_map_dma_area establishes two mappings in one go.
+ * These mappings point to pages normally mapped at 'va' (linear address).
+ * First mapping is for CPU visible address at 'a', uncached.
+ * This is an alias, but it works because it is an uncached mapping.
+ * Second mapping is for device visible address, or "bus" address.
+ * The bus address is returned at '*pba'.
+ *
+ * These functions seem distinct, but are hard to split. On sun4c,
+ * at least for now, 'a' is equal to bus address, and retured in *pba.
+ * On sun4m, page attributes depend on the CPU type, so we have to
+ * know if we are mapping RAM or I/O, so it has to be an additional argument
+ * to a separate mapping function for CPU visible mappings.
+ */
+BTFIXUPDEF_CALL(int, mmu_map_dma_area, struct device *, dma_addr_t *, unsigned long, unsigned long, int len)
+BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, struct device *, unsigned long busa, int len)
+
+#define mmu_map_dma_area(dev,pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(dev,pba,va,a,len)
+#define mmu_unmap_dma_area(dev,ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(dev,ba,len)
#endif
+
+#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_32.h b/arch/sparc/include/asm/dma_32.h
deleted file mode 100644
index cf7189c0079..00000000000
--- a/arch/sparc/include/asm/dma_32.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/* include/asm/dma.h
- *
- * Copyright 1995 (C) David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _ASM_SPARC_DMA_H
-#define _ASM_SPARC_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-#include <asm/vac-ops.h> /* for invalidate's, etc. */
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/spinlock.h>
-
-struct page;
-extern spinlock_t dma_spin_lock;
-
-static inline unsigned long claim_dma_lock(void)
-{
- unsigned long flags;
- spin_lock_irqsave(&dma_spin_lock, flags);
- return flags;
-}
-
-static inline void release_dma_lock(unsigned long flags)
-{
- spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define MAX_DMA_ADDRESS (~0UL)
-#define DMA_MODE_READ 1
-#define DMA_MODE_WRITE 2
-
-/* Useful constants */
-#define SIZE_16MB (16*1024*1024)
-#define SIZE_64K (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
-#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
-#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
-#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
-
-/* DVMA chip revisions */
-enum dvma_rev {
- dvmarev0,
- dvmaesc1,
- dvmarev1,
- dvmarev2,
- dvmarev3,
- dvmarevplus,
- dvmahme
-};
-
-#define DMA_HASCOUNT(rev) ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
- struct sbus_dma *next;
- struct sbus_dev *sdev;
- void __iomem *regs;
-
- /* Status, misc info */
- int node; /* Prom node for this DMA device */
- int running; /* Are we doing DMA now? */
- int allocated; /* Are we "owned" by anyone yet? */
-
- /* Transfer information. */
- unsigned long addr; /* Start address of current transfer */
- int nbytes; /* Size of current transfer */
- int realbytes; /* For splitting up large transfers, etc. */
-
- /* DMA revision */
- enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#ifdef CONFIG_SUN4
-/* Have to sort this out. Does rev0 work fine on sun4[cmd] without isbroken?
- * Or is rev0 present only on sun4 boxes? -jj */
-#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev0 || (dma)->revision == dvmarev1)
-#else
-#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev1)
-#endif
-#define DMA_ISESC1(dma) ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
-#define DMA_VERS0 0x00000000 /* Sunray DMA version */
-#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
-#define DMA_VERS1 0x80000000 /* DMA rev 1 */
-#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
-#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
-#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
-#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
-#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
-#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
-#define DMA_RST_BPP DMA_RST_SCSI /* Reset the BPP controller */
-#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
-#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
-#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
-#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
-#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64 0x00080000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32 0x00040000 /* SCSI/BPP: 32byte bursts */
-#define DMA_BRST16 0x00000000 /* SCSI/BPP: 16byte bursts */
-#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
-#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
-#define DMA_BPP_ON DMA_SCSI_ON /* Enable BPP dma */
-#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
-#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1 0x01
-#define DMA_BURST2 0x02
-#define DMA_BURST4 0x04
-#define DMA_BURST8 0x08
-#define DMA_BURST16 0x10
-#define DMA_BURST32 0x20
-#define DMA_BURST64 0x40
-#define DMA_BURSTBITS 0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs) ((((regs)->cond_reg) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs) ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
-#define DMA_WRITE_P(regs) ((((regs)->cond_reg) & DMA_ST_WRITE))
-#define DMA_OFF(regs) ((((regs)->cond_reg) &= (~DMA_ENABLE)))
-#define DMA_INTSOFF(regs) ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
-#define DMA_INTSON(regs) ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
-#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
-#define DMA_SETSTART(regs, addr) ((((regs)->st_addr) = (char *) addr))
-#define DMA_BEGINDMA_W(regs) \
- ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
-#define DMA_BEGINDMA_R(regs) \
- ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done. So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler. You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
- } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
- } while(0)
-
-#if 0 /* P3 this stuff is inline in ledma.c:init_restart_ledma() */
-/* Pause until counter runs out or BIT isn't set in the DMA condition
- * register.
- */
-static inline void sparc_dma_pause(struct sparc_dma_registers *regs,
- unsigned long bit)
-{
- int ctr = 50000; /* Let's find some bugs ;) */
-
- /* Busy wait until the bit is not set any more */
- while((regs->cond_reg&bit) && (ctr>0)) {
- ctr--;
- __delay(5);
- }
-
- /* Check for bogus outcome. */
- if(!ctr)
- panic("DMA timeout");
-}
-
-/* Reset the friggin' thing... */
-#define DMA_RESET(dma) do { \
- struct sparc_dma_registers *regs = dma->regs; \
- /* Let the current FIFO drain itself */ \
- sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN)); \
- /* Reset the logic */ \
- regs->cond_reg |= (DMA_RST_SCSI); /* assert */ \
- __delay(400); /* let the bits set ;) */ \
- regs->cond_reg &= ~(DMA_RST_SCSI); /* de-assert */ \
- sparc_dma_enable_interrupts(regs); /* Re-enable interrupts */ \
- /* Enable FAST transfers if available */ \
- if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS; \
- dma->running = 0; \
-} while(0)
-#endif
-
-#define for_each_dvma(dma) \
- for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-extern int get_dma_list(char *);
-extern int request_dma(unsigned int, __const__ char *);
-extern void free_dma(unsigned int);
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy (0)
-#endif
-
-/* Routines for data transfer buffers. */
-BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
-BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long)
-
-#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
-#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
-
-/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
-BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-
-#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus)
-#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus)
-#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus)
-#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus)
-
-/*
- * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
- *
- * The mmu_map_dma_area establishes two mappings in one go.
- * These mappings point to pages normally mapped at 'va' (linear address).
- * First mapping is for CPU visible address at 'a', uncached.
- * This is an alias, but it works because it is an uncached mapping.
- * Second mapping is for device visible address, or "bus" address.
- * The bus address is returned at '*pba'.
- *
- * These functions seem distinct, but are hard to split. On sun4c,
- * at least for now, 'a' is equal to bus address, and retured in *pba.
- * On sun4m, page attributes depend on the CPU type, so we have to
- * know if we are mapping RAM or I/O, so it has to be an additional argument
- * to a separate mapping function for CPU visible mappings.
- */
-BTFIXUPDEF_CALL(int, mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len)
-BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa)
-BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, unsigned long busa, int len)
-
-#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len)
-#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len)
-#define mmu_translate_dvma(ba) BTFIXUP_CALL(mmu_translate_dvma)(ba)
-
-#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_64.h b/arch/sparc/include/asm/dma_64.h
deleted file mode 100644
index 46a8aecffc0..00000000000
--- a/arch/sparc/include/asm/dma_64.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * include/asm/dma.h
- *
- * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _ASM_SPARC64_DMA_H
-#define _ASM_SPARC64_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define DMA_MODE_READ 1
-#define DMA_MODE_WRITE 2
-#define MAX_DMA_ADDRESS (~0UL)
-
-/* Useful constants */
-#define SIZE_16MB (16*1024*1024)
-#define SIZE_64K (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */
-#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */
-#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */
-#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */
-
-/* DVMA chip revisions */
-enum dvma_rev {
- dvmarev0,
- dvmaesc1,
- dvmarev1,
- dvmarev2,
- dvmarev3,
- dvmarevplus,
- dvmahme
-};
-
-#define DMA_HASCOUNT(rev) ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
- struct sbus_dma *next;
- struct sbus_dev *sdev;
- void __iomem *regs;
-
- /* Status, misc info */
- int node; /* Prom node for this DMA device */
- int running; /* Are we doing DMA now? */
- int allocated; /* Are we "owned" by anyone yet? */
-
- /* Transfer information. */
- u32 addr; /* Start address of current transfer */
- int nbytes; /* Size of current transfer */
- int realbytes; /* For splitting up large transfers, etc. */
-
- /* DMA revision */
- enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev1)
-#define DMA_ISESC1(dma) ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */
-#define DMA_VERS0 0x00000000 /* Sunray DMA version */
-#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */
-#define DMA_VERS1 0x80000000 /* DMA rev 1 */
-#define DMA_VERS2 0xa0000000 /* DMA rev 2 */
-#define DMA_VERHME 0xb0000000 /* DMA hme gate array */
-#define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */
-#define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */
-#define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */
-#define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */
-#define DMA_ST_WRITE 0x00000100 /* write from device to memory */
-#define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */
-#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST 0x00000800 /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD 0x00001800 /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */
-#define DMA_TERM_CNTR 0x00004000 /* Terminal counter */
-#define DMA_SCSI_SBUS64 0x00008000 /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS 0x000c0000 /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32 0x00040000 /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16 0x00000000 /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64 0x000c0000 /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32 0x00040000 /* SCSI: 32byte bursts */
-#define DMA_BRST16 0x00000000 /* SCSI: 16byte bursts */
-#define DMA_BRST0 0x00080000 /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */
-#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */
-#define DMA_PARITY_OFF 0x02000000 /* HME: disable parity checking */
-#define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000 /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1 0x01
-#define DMA_BURST2 0x02
-#define DMA_BURST4 0x04
-#define DMA_BURST8 0x08
-#define DMA_BURST16 0x10
-#define DMA_BURST32 0x20
-#define DMA_BURST64 0x40
-#define DMA_BURSTBITS 0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs) ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
-#define DMA_WRITE_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
-#define DMA_OFF(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp &= ~DMA_ENABLE; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSOFF(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp &= ~DMA_INT_ENAB; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSON(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= DMA_INT_ENAB; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_PUNTFIFO(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= DMA_FIFO_INV; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_SETSTART(__regs, __addr) \
- sbus_writel((u32)(__addr), (__regs) + DMA_ADDR);
-#define DMA_BEGINDMA_W(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB); \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_BEGINDMA_R(__regs) \
-do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \
- tmp |= (DMA_ENABLE|DMA_INT_ENAB); \
- tmp &= ~DMA_ST_WRITE; \
- sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done. So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler. You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
- } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
- if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
- } while(0)
-
-#define for_each_dvma(dma) \
- for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy (0)
-#endif
-
-#endif /* !(_ASM_SPARC64_DMA_H) */
diff --git a/arch/sparc/include/asm/ebus.h b/arch/sparc/include/asm/ebus.h
deleted file mode 100644
index 83a6d16c22e..00000000000
--- a/arch/sparc/include/asm/ebus.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_EBUS_H
-#define ___ASM_SPARC_EBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/ebus_64.h>
-#else
-#include <asm/ebus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/ebus_32.h b/arch/sparc/include/asm/ebus_32.h
deleted file mode 100644
index f91f0b267ce..00000000000
--- a/arch/sparc/include/asm/ebus_32.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- */
-
-#ifndef __SPARC_EBUS_H
-#define __SPARC_EBUS_H
-
-#ifndef _LINUX_IOPORT_H
-#include <linux/ioport.h>
-#endif
-#include <linux/of_device.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
- struct linux_ebus_child *next;
- struct linux_ebus_device *parent;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-
-struct linux_ebus_device {
- struct of_device ofdev;
- struct linux_ebus_device *next;
- struct linux_ebus_child *children;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
- struct of_device ofdev;
- struct linux_ebus *next;
- struct linux_ebus_device *devices;
- struct linux_pbm_info *parent;
- struct pci_dev *self;
- struct device_node *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct linux_ebus_dma {
- unsigned int dcsr;
- unsigned int dacr;
- unsigned int dbcr;
-};
-
-#define EBUS_DCSR_INT_PEND 0x00000001
-#define EBUS_DCSR_ERR_PEND 0x00000002
-#define EBUS_DCSR_DRAIN 0x00000004
-#define EBUS_DCSR_INT_EN 0x00000010
-#define EBUS_DCSR_RESET 0x00000080
-#define EBUS_DCSR_WRITE 0x00000100
-#define EBUS_DCSR_EN_DMA 0x00000200
-#define EBUS_DCSR_CYC_PEND 0x00000400
-#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
-#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
-#define EBUS_DCSR_EN_CNT 0x00002000
-#define EBUS_DCSR_TC 0x00004000
-#define EBUS_DCSR_DIS_CSR_DRN 0x00010000
-#define EBUS_DCSR_BURST_SZ_MASK 0x000c0000
-#define EBUS_DCSR_BURST_SZ_1 0x00080000
-#define EBUS_DCSR_BURST_SZ_4 0x00000000
-#define EBUS_DCSR_BURST_SZ_8 0x00040000
-#define EBUS_DCSR_BURST_SZ_16 0x000c0000
-#define EBUS_DCSR_DIAG_EN 0x00100000
-#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
-#define EBUS_DCSR_TCI_DIS 0x00800000
-#define EBUS_DCSR_EN_NEXT 0x01000000
-#define EBUS_DCSR_DMA_ON 0x02000000
-#define EBUS_DCSR_A_LOADED 0x04000000
-#define EBUS_DCSR_NA_LOADED 0x08000000
-#define EBUS_DCSR_DEV_ID_MASK 0xf0000000
-
-extern struct linux_ebus *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus) \
- for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus) \
- for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child) \
- for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_64.h b/arch/sparc/include/asm/ebus_64.h
deleted file mode 100644
index 14c6a111f60..00000000000
--- a/arch/sparc/include/asm/ebus_64.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#ifndef __SPARC64_EBUS_H
-#define __SPARC64_EBUS_H
-
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
- struct linux_ebus_child *next;
- struct linux_ebus_device *parent;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-
-struct linux_ebus_device {
- struct of_device ofdev;
- struct linux_ebus_device *next;
- struct linux_ebus_child *children;
- struct linux_ebus *bus;
- struct device_node *prom_node;
- struct resource resource[PROMREG_MAX];
- int num_addrs;
- unsigned int irqs[PROMINTR_MAX];
- int num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
- struct of_device ofdev;
- struct linux_ebus *next;
- struct linux_ebus_device *devices;
- struct pci_dev *self;
- int index;
- int is_rio;
- struct device_node *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct ebus_dma_info {
- spinlock_t lock;
- void __iomem *regs;
-
- unsigned int flags;
-#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001
-#define EBUS_DMA_FLAG_TCI_DISABLE 0x00000002
-
- /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
- * set.
- */
- void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
- void *client_cookie;
- unsigned int irq;
-#define EBUS_DMA_EVENT_ERROR 1
-#define EBUS_DMA_EVENT_DMA 2
-#define EBUS_DMA_EVENT_DEVICE 4
-
- unsigned char name[64];
-};
-
-extern int ebus_dma_register(struct ebus_dma_info *p);
-extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
-extern void ebus_dma_unregister(struct ebus_dma_info *p);
-extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
- size_t len);
-extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
-extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
-extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
-extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
-
-extern struct linux_ebus *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus) \
- for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus) \
- for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child) \
- for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC64_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_dma.h b/arch/sparc/include/asm/ebus_dma.h
new file mode 100644
index 00000000000..f07a5b541c9
--- /dev/null
+++ b/arch/sparc/include/asm/ebus_dma.h
@@ -0,0 +1,35 @@
+#ifndef __ASM_SPARC_EBUS_DMA_H
+#define __ASM_SPARC_EBUS_DMA_H
+
+struct ebus_dma_info {
+ spinlock_t lock;
+ void __iomem *regs;
+
+ unsigned int flags;
+#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER 0x00000001
+#define EBUS_DMA_FLAG_TCI_DISABLE 0x00000002
+
+ /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
+ * set.
+ */
+ void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
+ void *client_cookie;
+ unsigned int irq;
+#define EBUS_DMA_EVENT_ERROR 1
+#define EBUS_DMA_EVENT_DMA 2
+#define EBUS_DMA_EVENT_DEVICE 4
+
+ unsigned char name[64];
+};
+
+extern int ebus_dma_register(struct ebus_dma_info *p);
+extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
+extern void ebus_dma_unregister(struct ebus_dma_info *p);
+extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
+ size_t len);
+extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
+extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
+extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
+extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
+
+#endif /* __ASM_SPARC_EBUS_DMA_H */
diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_32.h
index d043f80bc2f..b7ab6054782 100644
--- a/arch/sparc/include/asm/elf_32.h
+++ b/arch/sparc/include/asm/elf_32.h
@@ -105,11 +105,8 @@ typedef struct {
#define ELF_DATA ELFDATA2MSB
#define USE_ELF_CORE_DUMP
-#ifndef CONFIG_SUN4
+
#define ELF_EXEC_PAGESIZE 4096
-#else
-#define ELF_EXEC_PAGESIZE 8192
-#endif
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
@@ -126,7 +123,7 @@ typedef struct {
/* Sun4c has none of the capabilities, most sun4m's have them all.
* XXX This is gross, set some global variable at boot time. -DaveM
*/
-#define ELF_HWCAP ((ARCH_SUN4C_SUN4) ? 0 : \
+#define ELF_HWCAP ((ARCH_SUN4C) ? 0 : \
(HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
HWCAP_SPARC_SWAP | \
((srmmu_modtype != Cypress && \
diff --git a/arch/sparc/include/asm/fhc.h b/arch/sparc/include/asm/fhc.h
index 788cbc46a11..57f1b303ad5 100644
--- a/arch/sparc/include/asm/fhc.h
+++ b/arch/sparc/include/asm/fhc.h
@@ -1,5 +1,4 @@
-/*
- * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+/* fhc.h: FHC and Clock board register definitions.
*
* Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
*/
@@ -7,14 +6,6 @@
#ifndef _SPARC64_FHC_H
#define _SPARC64_FHC_H
-#include <linux/timer.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/upa.h>
-
-struct linux_fhc;
-
/* Clock board register offsets. */
#define CLOCK_CTRL 0x00UL /* Main control */
#define CLOCK_STAT1 0x10UL /* Status one */
@@ -29,21 +20,7 @@ struct linux_fhc;
#define CLOCK_CTRL_MLED 0x02 /* Mid LED, 1 == on */
#define CLOCK_CTRL_RLED 0x01 /* RIght LED, 1 == on */
-struct linux_central {
- struct linux_fhc *child;
- unsigned long cfreg;
- unsigned long clkregs;
- unsigned long clkver;
- int slots;
- struct device_node *prom_node;
-
- struct linux_prom_ranges central_ranges[PROMREG_MAX];
- int num_central_ranges;
-};
-
/* Firehose controller register offsets */
-struct fhc_regs {
- unsigned long pregs; /* FHC internal regs */
#define FHC_PREGS_ID 0x00UL /* FHC ID */
#define FHC_ID_VERS 0xf0000000 /* Version of this FHC */
#define FHC_ID_PARTID 0x0ffff000 /* Part ID code (0x0f9f == FHC) */
@@ -90,32 +67,14 @@ struct fhc_regs {
#define FHC_JTAG_CTRL_MENAB 0x80000000 /* Indicates this is JTAG Master */
#define FHC_JTAG_CTRL_MNONE 0x40000000 /* Indicates no JTAG Master present */
#define FHC_PREGS_JCMD 0x100UL /* FHC JTAG Command Register */
- unsigned long ireg; /* FHC IGN reg */
#define FHC_IREG_IGN 0x00UL /* This FHC's IGN */
- unsigned long ffregs; /* FHC fanfail regs */
#define FHC_FFREGS_IMAP 0x00UL /* FHC Fanfail IMAP */
#define FHC_FFREGS_ICLR 0x10UL /* FHC Fanfail ICLR */
- unsigned long sregs; /* FHC system regs */
#define FHC_SREGS_IMAP 0x00UL /* FHC System IMAP */
#define FHC_SREGS_ICLR 0x10UL /* FHC System ICLR */
- unsigned long uregs; /* FHC uart regs */
#define FHC_UREGS_IMAP 0x00UL /* FHC Uart IMAP */
#define FHC_UREGS_ICLR 0x10UL /* FHC Uart ICLR */
- unsigned long tregs; /* FHC TOD regs */
#define FHC_TREGS_IMAP 0x00UL /* FHC TOD IMAP */
#define FHC_TREGS_ICLR 0x10UL /* FHC TOD ICLR */
-};
-
-struct linux_fhc {
- struct linux_fhc *next;
- struct linux_central *parent; /* NULL if not central FHC */
- struct fhc_regs fhc_regs;
- int board;
- int jtag_master;
- struct device_node *prom_node;
-
- struct linux_prom_ranges fhc_ranges[PROMREG_MAX];
- int num_fhc_ranges;
-};
#endif /* !(_SPARC64_FHC_H) */
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index ae3f00bf22f..c792830636d 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -6,6 +6,9 @@
#ifndef __ASM_SPARC_FLOPPY_H
#define __ASM_SPARC_FLOPPY_H
+#include <linux/of.h>
+#include <linux/of_device.h>
+
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -343,7 +346,7 @@ static int sun_floppy_init(void)
r.flags = fd_regs[0].which_io;
r.start = fd_regs[0].phys_addr;
sun_fdc = (struct sun_flpy_controller *)
- sbus_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
+ of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
/* Last minute sanity check... */
if(sun_fdc->status_82072 == 0xff) {
@@ -385,4 +388,15 @@ static int sparc_eject(void)
#define EXTRA_FLOPPY_PARAMS
+static DEFINE_SPINLOCK(dma_spin_lock);
+
+#define claim_dma_lock() \
+({ unsigned long flags; \
+ spin_lock_irqsave(&dma_spin_lock, flags); \
+ flags; \
+})
+
+#define release_dma_lock(__flags) \
+ spin_unlock_irqrestore(&dma_spin_lock, __flags);
+
#endif /* !(__ASM_SPARC_FLOPPY_H) */
diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h
index c39db1060bc..36439d67ad7 100644
--- a/arch/sparc/include/asm/floppy_64.h
+++ b/arch/sparc/include/asm/floppy_64.h
@@ -1,6 +1,6 @@
/* floppy.h: Sparc specific parts of the Floppy driver.
*
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*
* Ultra/PCI support added: Sep 1997 Eddie C. Dost (ecd@skynet.be)
@@ -9,18 +9,11 @@
#ifndef __ASM_SPARC64_FLOPPY_H
#define __ASM_SPARC64_FLOPPY_H
-#include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/idprom.h>
-#include <asm/oplib.h>
#include <asm/auxio.h>
-#include <asm/sbus.h>
-#include <asm/irq.h>
-
/*
* Define this to enable exchanging drive 0 and 1 if only drive 1 is
@@ -50,7 +43,7 @@ struct sun_flpy_controller {
/* You'll only ever find one controller on an Ultra anyways. */
static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
unsigned long fdc_status;
-static struct sbus_dev *floppy_sdev = NULL;
+static struct of_device *floppy_op = NULL;
struct sun_floppy_ops {
unsigned char (*fd_inb) (unsigned long port);
@@ -291,12 +284,11 @@ static int sun_fd_eject(int drive)
return 0;
}
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
#include <asm/ns87303.h>
static struct ebus_dma_info sun_pci_fd_ebus_dma;
-static struct pci_dev *sun_pci_ebus_dev;
+static struct device *sun_floppy_dev;
static int sun_pci_broken_drive = -1;
struct sun_pci_dma_op {
@@ -377,7 +369,7 @@ static void sun_pci_fd_enable_dma(void)
sun_pci_dma_pending.addr = -1U;
sun_pci_dma_current.addr =
- pci_map_single(sun_pci_ebus_dev,
+ dma_map_single(sun_floppy_dev,
sun_pci_dma_current.buf,
sun_pci_dma_current.len,
sun_pci_dma_current.direction);
@@ -394,7 +386,7 @@ static void sun_pci_fd_disable_dma(void)
{
ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
if (sun_pci_dma_current.addr != -1U)
- pci_unmap_single(sun_pci_ebus_dev,
+ dma_unmap_single(sun_floppy_dev,
sun_pci_dma_current.addr,
sun_pci_dma_current.len,
sun_pci_dma_current.direction);
@@ -404,9 +396,9 @@ static void sun_pci_fd_disable_dma(void)
static void sun_pci_fd_set_dma_mode(int mode)
{
if (mode == DMA_MODE_WRITE)
- sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
+ sun_pci_dma_pending.direction = DMA_TO_DEVICE;
else
- sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
+ sun_pci_dma_pending.direction = DMA_FROM_DEVICE;
ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
}
@@ -538,80 +530,84 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive)
#undef MSR
#undef DOR
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
+static int __init ebus_fdthree_p(struct device_node *dp)
{
- if (!strcmp(edev->prom_node->name, "fdthree"))
+ if (!strcmp(dp->name, "fdthree"))
return 1;
- if (!strcmp(edev->prom_node->name, "floppy")) {
+ if (!strcmp(dp->name, "floppy")) {
const char *compat;
- compat = of_get_property(edev->prom_node,
- "compatible", NULL);
+ compat = of_get_property(dp, "compatible", NULL);
if (compat && !strcmp(compat, "fdthree"))
return 1;
}
return 0;
}
-#endif
static unsigned long __init sun_floppy_init(void)
{
- char state[128];
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
static int initialized = 0;
+ struct device_node *dp;
+ struct of_device *op;
+ const char *prop;
+ char state[128];
if (initialized)
return sun_floppy_types[0];
initialized = 1;
- for_all_sbusdev (sdev, bus) {
- if (!strcmp(sdev->prom_name, "SUNW,fdtwo"))
+ op = NULL;
+
+ for_each_node_by_name(dp, "SUNW,fdtwo") {
+ if (strcmp(dp->parent->name, "sbus"))
+ continue;
+ op = of_find_device_by_node(dp);
+ if (op)
break;
}
- if(sdev) {
- floppy_sdev = sdev;
- FLOPPY_IRQ = sdev->irqs[0];
+ if (op) {
+ floppy_op = op;
+ FLOPPY_IRQ = op->irqs[0];
} else {
-#ifdef CONFIG_PCI
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev = NULL;
- unsigned long config = 0;
+ struct device_node *ebus_dp;
void __iomem *auxio_reg;
const char *state_prop;
+ unsigned long config;
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (ebus_fdthree_p(edev))
- goto ebus_done;
+ dp = NULL;
+ for_each_node_by_name(ebus_dp, "ebus") {
+ for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+ if (ebus_fdthree_p(dp))
+ goto found_fdthree;
}
}
- ebus_done:
- if (!edev)
+ found_fdthree:
+ if (!dp)
+ return 0;
+
+ op = of_find_device_by_node(dp);
+ if (!op)
return 0;
- state_prop = of_get_property(edev->prom_node, "status", NULL);
+ state_prop = of_get_property(op->node, "status", NULL);
if (state_prop && !strncmp(state_prop, "disabled", 8))
return 0;
- FLOPPY_IRQ = edev->irqs[0];
+ FLOPPY_IRQ = op->irqs[0];
/* Make sure the high density bit is set, some systems
* (most notably Ultra5/Ultra10) come up with it clear.
*/
- auxio_reg = (void __iomem *) edev->resource[2].start;
+ auxio_reg = (void __iomem *) op->resource[2].start;
writel(readl(auxio_reg)|0x2, auxio_reg);
- sun_pci_ebus_dev = ebus->self;
+ sun_floppy_dev = &op->dev;
spin_lock_init(&sun_pci_fd_ebus_dma.lock);
/* XXX ioremap */
sun_pci_fd_ebus_dma.regs = (void __iomem *)
- edev->resource[1].start;
+ op->resource[1].start;
if (!sun_pci_fd_ebus_dma.regs)
return 0;
@@ -625,7 +621,7 @@ static unsigned long __init sun_floppy_init(void)
return 0;
/* XXX ioremap */
- sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
+ sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;
sun_fdops.fd_inb = sun_pci_fd_inb;
sun_fdops.fd_outb = sun_pci_fd_outb;
@@ -662,12 +658,15 @@ static unsigned long __init sun_floppy_init(void)
/*
* Find NS87303 SuperIO config registers (through ecpp).
*/
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "ecpp")) {
- config = edev->resource[1].start;
- goto config_done;
- }
+ config = 0;
+ for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+ if (!strcmp(dp->name, "ecpp")) {
+ struct of_device *ecpp_op;
+
+ ecpp_op = of_find_device_by_node(dp);
+ if (ecpp_op)
+ config = ecpp_op->resource[1].start;
+ goto config_done;
}
}
config_done:
@@ -716,26 +715,23 @@ static unsigned long __init sun_floppy_init(void)
#endif /* PCI_FDC_SWAP_DRIVES */
return sun_floppy_types[0];
-#else
- return 0;
-#endif
}
- prom_getproperty(sdev->prom_node, "status", state, sizeof(state));
- if(!strncmp(state, "disabled", 8))
+ prop = of_get_property(op->node, "status", NULL);
+ if (prop && !strncmp(state, "disabled", 8))
return 0;
/*
- * We cannot do sbus_ioremap here: it does request_region,
+ * We cannot do of_ioremap here: it does request_region,
* which the generic floppy driver tries to do once again.
* But we must use the sdev resource values as they have
* had parent ranges applied.
*/
sun_fdc = (struct sun_flpy_controller *)
- (sdev->resource[0].start +
- ((sdev->resource[0].flags & 0x1ffUL) << 32UL));
+ (op->resource[0].start +
+ ((op->resource[0].flags & 0x1ffUL) << 32UL));
/* Last minute sanity check... */
- if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
+ if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
sun_fdc = (struct sun_flpy_controller *)-1;
return 0;
}
diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h
new file mode 100644
index 00000000000..a0e3ac0af59
--- /dev/null
+++ b/arch/sparc/include/asm/gpio.h
@@ -0,0 +1,36 @@
+#ifndef __ASM_SPARC_GPIO_H
+#define __ASM_SPARC_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* __ASM_SPARC_GPIO_H */
diff --git a/arch/sparc/include/asm/io-unit.h b/arch/sparc/include/asm/io-unit.h
index 96823b47fd4..01ab2f613e9 100644
--- a/arch/sparc/include/asm/io-unit.h
+++ b/arch/sparc/include/asm/io-unit.h
@@ -55,8 +55,4 @@ struct iounit_struct {
#define IOUNIT_BMAPM_START IOUNIT_BMAP2_END
#define IOUNIT_BMAPM_END ((IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE) >> PAGE_SHIFT)
-extern __u32 iounit_map_dma_init(struct sbus_bus *, int);
-#define iounit_map_dma_finish(sbus, addr, len) mmu_release_scsi_one(addr, len, sbus)
-extern __u32 iounit_map_dma_page(__u32, void *, struct sbus_bus *);
-
#endif /* !(_SPARC_IO_UNIT_H) */
diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index 10d7da45007..93fe21e02c8 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -293,14 +293,6 @@ extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
/*
- * Bus number may be in res->flags... somewhere.
- */
-extern void __iomem *sbus_ioremap(struct resource *res, unsigned long offset,
- unsigned long size, char *name);
-extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
-
-
-/*
* At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
* so rtc_port is static in it. This should not change unless a new
* hardware pops up.
@@ -308,6 +300,17 @@ extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
#define RTC_PORT(x) (rtc_port + (x))
#define RTC_ALWAYS_BCD 0
+static inline int sbus_can_dma_64bit(void)
+{
+ return 0; /* actually, sparc_cpu_model==sun4d */
+}
+static inline int sbus_can_burst64(void)
+{
+ return 0; /* actually, sparc_cpu_model==sun4d */
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
+
#endif
#define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1
diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 0bff078ffdd..4aee21dc9c6 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -482,18 +482,16 @@ struct pci_dev;
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
-/* Similarly for SBUS. */
-#define sbus_ioremap(__res, __offset, __size, __name) \
-({ unsigned long __ret; \
- __ret = (__res)->start + (((__res)->flags & 0x1ffUL) << 32UL); \
- __ret += (unsigned long) (__offset); \
- if (! request_region((__ret), (__size), (__name))) \
- __ret = 0UL; \
- (void __iomem *) __ret; \
-})
-
-#define sbus_iounmap(__addr, __size) \
- release_region((unsigned long)(__addr), (__size))
+static inline int sbus_can_dma_64bit(void)
+{
+ return 1;
+}
+static inline int sbus_can_burst64(void)
+{
+ return 1;
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
diff --git a/arch/sparc/include/asm/iommu_64.h b/arch/sparc/include/asm/iommu_64.h
index d7b9afcba08..caf798b5619 100644
--- a/arch/sparc/include/asm/iommu_64.h
+++ b/arch/sparc/include/asm/iommu_64.h
@@ -48,6 +48,9 @@ struct strbuf {
unsigned long strbuf_control;
unsigned long strbuf_pflush;
unsigned long strbuf_fsync;
+ unsigned long strbuf_err_stat;
+ unsigned long strbuf_tag_diag;
+ unsigned long strbuf_line_diag;
unsigned long strbuf_ctxflush;
unsigned long strbuf_ctxmatch_base;
unsigned long strbuf_flushflag_pa;
diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h
index e3dd9303643..71673eca366 100644
--- a/arch/sparc/include/asm/irq_64.h
+++ b/arch/sparc/include/asm/irq_64.h
@@ -56,7 +56,6 @@ extern unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
unsigned long imap_base,
unsigned long iclr_base);
extern void sun4u_destroy_msi(unsigned int virt_irq);
-extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
extern unsigned char virt_irq_alloc(unsigned int dev_handle,
unsigned int dev_ino);
diff --git a/arch/sparc/include/asm/mc146818rtc_64.h b/arch/sparc/include/asm/mc146818rtc_64.h
index e9c0fcc25c6..7238d174e0e 100644
--- a/arch/sparc/include/asm/mc146818rtc_64.h
+++ b/arch/sparc/include/asm/mc146818rtc_64.h
@@ -7,12 +7,8 @@
#include <asm/io.h>
#ifndef RTC_PORT
-#ifdef CONFIG_PCI
-extern unsigned long ds1287_regs;
-#else
-#define ds1287_regs (0UL)
-#endif
-#define RTC_PORT(x) (ds1287_regs + (x))
+extern unsigned long cmos_regs;
+#define RTC_PORT(x) (cmos_regs + (x))
#define RTC_ALWAYS_BCD 0
#endif
@@ -29,6 +25,4 @@ outb_p((addr),RTC_PORT(0)); \
outb_p((val),RTC_PORT(1)); \
})
-#define RTC_IRQ 8
-
#endif /* __ASM_SPARC64_MC146818RTC_H */
diff --git a/arch/sparc/include/asm/memctrl.h b/arch/sparc/include/asm/memctrl.h
new file mode 100644
index 00000000000..4065c56af7b
--- /dev/null
+++ b/arch/sparc/include/asm/memctrl.h
@@ -0,0 +1,9 @@
+#ifndef _SPARC_MEMCTRL_H
+#define _SPARC_MEMCTRL_H
+
+typedef int (*dimm_printer_t)(int synd_code, unsigned long paddr, char *buf, int buflen);
+
+int register_dimm_printer(dimm_printer_t func);
+void unregister_dimm_printer(dimm_printer_t func);
+
+#endif /* _SPARC_MEMCTRL_H */
diff --git a/arch/sparc/include/asm/mostek.h b/arch/sparc/include/asm/mostek.h
deleted file mode 100644
index 433be3e0a69..00000000000
--- a/arch/sparc/include/asm/mostek.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_MOSTEK_H
-#define ___ASM_SPARC_MOSTEK_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/mostek_64.h>
-#else
-#include <asm/mostek_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/mostek_32.h b/arch/sparc/include/asm/mostek_32.h
deleted file mode 100644
index a99590c4c50..00000000000
--- a/arch/sparc/include/asm/mostek_32.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * mostek.h: Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- * Added intersil code 05/25/98 Chris Davis (cdavis@cois.on.ca)
- */
-
-#ifndef _SPARC_MOSTEK_H
-#define _SPARC_MOSTEK_H
-
-#include <asm/idprom.h>
-#include <asm/io.h>
-
-/* M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- * Data
- * Address Function
- * Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- * 7ff - - - - - - - - Year 00-99
- * 7fe 0 0 0 - - - - - Month 01-12
- * 7fd 0 0 - - - - - - Date 01-31
- * 7fc 0 FT 0 0 0 - - - Day 01-07
- * 7fb KS 0 - - - - - - Hours 00-23
- * 7fa 0 - - - - - - - Minutes 00-59
- * 7f9 ST - - - - - - - Seconds 00-59
- * 7f8 W R S - - - - - Control
- *
- * * ST is STOP BIT
- * * W is WRITE BIT
- * * R is READ BIT
- * * S is SIGN BIT
- * * FT is FREQ TEST BIT
- * * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- */
-#define mostek_read(_addr) readb(_addr)
-#define mostek_write(_addr,_val) writeb(_val, _addr)
-#define MOSTEK_EEPROM 0x0000UL
-#define MOSTEK_IDPROM 0x07d8UL
-#define MOSTEK_CREG 0x07f8UL
-#define MOSTEK_SEC 0x07f9UL
-#define MOSTEK_MIN 0x07faUL
-#define MOSTEK_HOUR 0x07fbUL
-#define MOSTEK_DOW 0x07fcUL
-#define MOSTEK_DOM 0x07fdUL
-#define MOSTEK_MONTH 0x07feUL
-#define MOSTEK_YEAR 0x07ffUL
-
-struct mostek48t02 {
- volatile char eeprom[2008]; /* This is the eeprom, don't touch! */
- struct idprom idprom; /* The idprom lives here. */
- volatile unsigned char creg; /* Control register */
- volatile unsigned char sec; /* Seconds (0-59) */
- volatile unsigned char min; /* Minutes (0-59) */
- volatile unsigned char hour; /* Hour (0-23) */
- volatile unsigned char dow; /* Day of the week (1-7) */
- volatile unsigned char dom; /* Day of the month (1-31) */
- volatile unsigned char month; /* Month of year (1-12) */
- volatile unsigned char year; /* Year (0-99) */
-};
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */
-#define MSTK_CREG_READ 0x40 /* Stop updates to allow a clean read. */
-#define MSTK_CREG_SIGN 0x20 /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define MSTK_STOP 0x80 /* Stop the clock oscillator. (sec) */
-#define MSTK_KICK_START 0x80 /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40 /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO 1968 /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr) ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define MSTK_SEC_MASK 0x7f
-#define MSTK_MIN_MASK 0x7f
-#define MSTK_HOUR_MASK 0x3f
-#define MSTK_DOW_MASK 0x07
-#define MSTK_DOM_MASK 0x3f
-#define MSTK_MONTH_MASK 0x1f
-#define MSTK_YEAR_MASK 0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x) ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK))
-#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define MSTK_REG_CREG(regs) (((struct mostek48t02 *)regs)->creg)
-#define MSTK_REG_SEC(regs) MSTK_GET(regs,sec,SEC)
-#define MSTK_REG_MIN(regs) MSTK_GET(regs,min,MIN)
-#define MSTK_REG_HOUR(regs) MSTK_GET(regs,hour,HOUR)
-#define MSTK_REG_DOW(regs) MSTK_GET(regs,dow,DOW)
-#define MSTK_REG_DOM(regs) MSTK_GET(regs,dom,DOM)
-#define MSTK_REG_MONTH(regs) MSTK_GET(regs,month,MONTH)
-#define MSTK_REG_YEAR(regs) MSTK_GET(regs,year,YEAR)
-
-#define MSTK_SET_REG_SEC(regs,value) MSTK_SET(regs,sec,value,SEC)
-#define MSTK_SET_REG_MIN(regs,value) MSTK_SET(regs,min,value,MIN)
-#define MSTK_SET_REG_HOUR(regs,value) MSTK_SET(regs,hour,value,HOUR)
-#define MSTK_SET_REG_DOW(regs,value) MSTK_SET(regs,dow,value,DOW)
-#define MSTK_SET_REG_DOM(regs,value) MSTK_SET(regs,dom,value,DOM)
-#define MSTK_SET_REG_MONTH(regs,value) MSTK_SET(regs,month,value,MONTH)
-#define MSTK_SET_REG_YEAR(regs,value) MSTK_SET(regs,year,value,YEAR)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-struct mostek48t08 {
- char offset[6*1024]; /* Magic things may be here, who knows? */
- struct mostek48t02 regs; /* Here is what we are interested in. */
-};
-
-#ifdef CONFIG_SUN4
-enum sparc_clock_type { MSTK48T02, MSTK48T08, \
-INTERSIL, MSTK_INVALID };
-#else
-enum sparc_clock_type { MSTK48T02, MSTK48T08, \
-MSTK_INVALID };
-#endif
-
-#ifdef CONFIG_SUN4
-/* intersil on a sun 4/260 code data from harris doc */
-struct intersil_dt {
- volatile unsigned char int_csec;
- volatile unsigned char int_hour;
- volatile unsigned char int_min;
- volatile unsigned char int_sec;
- volatile unsigned char int_month;
- volatile unsigned char int_day;
- volatile unsigned char int_year;
- volatile unsigned char int_dow;
-};
-
-struct intersil {
- struct intersil_dt clk;
- struct intersil_dt cmp;
- volatile unsigned char int_intr_reg;
- volatile unsigned char int_cmd_reg;
-};
-
-#define INTERSIL_STOP 0x0
-#define INTERSIL_START 0x8
-#define INTERSIL_INTR_DISABLE 0x0
-#define INTERSIL_INTR_ENABLE 0x10
-#define INTERSIL_32K 0x0
-#define INTERSIL_NORMAL 0x0
-#define INTERSIL_24H 0x4
-#define INTERSIL_INT_100HZ 0x2
-
-/* end of intersil info */
-#endif
-
-#endif /* !(_SPARC_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/mostek_64.h b/arch/sparc/include/asm/mostek_64.h
deleted file mode 100644
index c5652de2ace..00000000000
--- a/arch/sparc/include/asm/mostek_64.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/* mostek.h: Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _SPARC64_MOSTEK_H
-#define _SPARC64_MOSTEK_H
-
-#include <asm/idprom.h>
-
-/* M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- * Data
- * Address Function
- * Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- * 7ff - - - - - - - - Year 00-99
- * 7fe 0 0 0 - - - - - Month 01-12
- * 7fd 0 0 - - - - - - Date 01-31
- * 7fc 0 FT 0 0 0 - - - Day 01-07
- * 7fb KS 0 - - - - - - Hours 00-23
- * 7fa 0 - - - - - - - Minutes 00-59
- * 7f9 ST - - - - - - - Seconds 00-59
- * 7f8 W R S - - - - - Control
- *
- * * ST is STOP BIT
- * * W is WRITE BIT
- * * R is READ BIT
- * * S is SIGN BIT
- * * FT is FREQ TEST BIT
- * * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- *
- * We now deal with physical addresses for I/O to the chip. -DaveM
- */
-static inline u8 mostek_read(void __iomem *addr)
-{
- u8 ret;
-
- __asm__ __volatile__("lduba [%1] %2, %0"
- : "=r" (ret)
- : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
- return ret;
-}
-
-static inline void mostek_write(void __iomem *addr, u8 val)
-{
- __asm__ __volatile__("stba %0, [%1] %2"
- : /* no outputs */
- : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-}
-
-#define MOSTEK_EEPROM 0x0000UL
-#define MOSTEK_IDPROM 0x07d8UL
-#define MOSTEK_CREG 0x07f8UL
-#define MOSTEK_SEC 0x07f9UL
-#define MOSTEK_MIN 0x07faUL
-#define MOSTEK_HOUR 0x07fbUL
-#define MOSTEK_DOW 0x07fcUL
-#define MOSTEK_DOM 0x07fdUL
-#define MOSTEK_MONTH 0x07feUL
-#define MOSTEK_YEAR 0x07ffUL
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */
-#define MSTK_CREG_READ 0x40 /* Stop updates to allow a clean read. */
-#define MSTK_CREG_SIGN 0x20 /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define MSTK_STOP 0x80 /* Stop the clock oscillator. (sec) */
-#define MSTK_KICK_START 0x80 /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40 /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO 1968 /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr) ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define MSTK_SEC_MASK 0x7f
-#define MSTK_MIN_MASK 0x7f
-#define MSTK_HOUR_MASK 0x3f
-#define MSTK_DOW_MASK 0x07
-#define MSTK_DOM_MASK 0x3f
-#define MSTK_MONTH_MASK 0x1f
-#define MSTK_YEAR_MASK 0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x) (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x) ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,name) \
- (MSTK_REGVAL_TO_DECIMAL(mostek_read(regs + MOSTEK_ ## name) & MSTK_ ## name ## _MASK))
-#define MSTK_SET(regs,name,value) \
-do { u8 __val = mostek_read(regs + MOSTEK_ ## name); \
- __val &= ~(MSTK_ ## name ## _MASK); \
- __val |= (MSTK_DECIMAL_TO_REGVAL(value) & \
- (MSTK_ ## name ## _MASK)); \
- mostek_write(regs + MOSTEK_ ## name, __val); \
-} while(0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define MSTK_REG_CREG(regs) (mostek_read((regs) + MOSTEK_CREG))
-#define MSTK_REG_SEC(regs) MSTK_GET(regs,SEC)
-#define MSTK_REG_MIN(regs) MSTK_GET(regs,MIN)
-#define MSTK_REG_HOUR(regs) MSTK_GET(regs,HOUR)
-#define MSTK_REG_DOW(regs) MSTK_GET(regs,DOW)
-#define MSTK_REG_DOM(regs) MSTK_GET(regs,DOM)
-#define MSTK_REG_MONTH(regs) MSTK_GET(regs,MONTH)
-#define MSTK_REG_YEAR(regs) MSTK_GET(regs,YEAR)
-
-#define MSTK_SET_REG_SEC(regs,value) MSTK_SET(regs,SEC,value)
-#define MSTK_SET_REG_MIN(regs,value) MSTK_SET(regs,MIN,value)
-#define MSTK_SET_REG_HOUR(regs,value) MSTK_SET(regs,HOUR,value)
-#define MSTK_SET_REG_DOW(regs,value) MSTK_SET(regs,DOW,value)
-#define MSTK_SET_REG_DOM(regs,value) MSTK_SET(regs,DOM,value)
-#define MSTK_SET_REG_MONTH(regs,value) MSTK_SET(regs,MONTH,value)
-#define MSTK_SET_REG_YEAR(regs,value) MSTK_SET(regs,YEAR,value)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-#define MOSTEK_48T08_OFFSET 0x0000UL /* Lower NVRAM portions */
-#define MOSTEK_48T08_48T02 0x1800UL /* Offset to 48T02 chip */
-
-/* SUN5 systems usually have 48t59 model clock chipsets. But we keep the older
- * clock chip definitions around just in case.
- */
-#define MOSTEK_48T59_OFFSET 0x0000UL /* Lower NVRAM portions */
-#define MOSTEK_48T59_48T02 0x1800UL /* Offset to 48T02 chip */
-
-#endif /* !(_SPARC64_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/obio.h b/arch/sparc/include/asm/obio.h
index 1a7544ceb57..4ade0c8a2c7 100644
--- a/arch/sparc/include/asm/obio.h
+++ b/arch/sparc/include/asm/obio.h
@@ -155,17 +155,6 @@ static inline void bw_set_ctrl(int cpu, unsigned ctrl)
"i" (ASI_M_CTL));
}
-extern unsigned char cpu_leds[32];
-
-static inline void show_leds(int cpuid)
-{
- cpuid &= 0x1e;
- __asm__ __volatile__ ("stba %0, [%1] %2" : :
- "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
- "r" (ECSR_BASE(cpuid) | BB_LEDS),
- "i" (ASI_M_CTL));
-}
-
static inline unsigned cc_get_ipen(void)
{
unsigned pending;
diff --git a/arch/sparc/include/asm/of_device.h b/arch/sparc/include/asm/of_device.h
index bba777a416d..a5d9811f969 100644
--- a/arch/sparc/include/asm/of_device.h
+++ b/arch/sparc/include/asm/of_device.h
@@ -30,6 +30,8 @@ struct of_device
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
+extern void of_propagate_archdata(struct of_device *bus);
+
/* This is just here during the transition */
#include <linux/of_platform.h>
diff --git a/arch/sparc/include/asm/of_platform.h b/arch/sparc/include/asm/of_platform.h
index 2348ab90a57..90da99059f8 100644
--- a/arch/sparc/include/asm/of_platform.h
+++ b/arch/sparc/include/asm/of_platform.h
@@ -13,9 +13,6 @@
*
*/
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-
#define of_bus_type of_platform_bus_type /* for compatibility */
#endif
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h
index b2631da259e..699da05235c 100644
--- a/arch/sparc/include/asm/oplib_32.h
+++ b/arch/sparc/include/asm/oplib_32.h
@@ -21,7 +21,6 @@ enum prom_major_version {
PROM_V2, /* sun4c and early sun4m V2 prom */
PROM_V3, /* sun4m and later, up to sun4d/sun4e machines V3 */
PROM_P1275, /* IEEE compliant ISA based Sun PROM, only sun4u */
- PROM_SUN4, /* Old sun4 proms are totally different, but we'll shoehorn it to make it fit */
};
extern enum prom_major_version prom_vers;
diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h
index cf5fb70ca1c..d1806edc095 100644
--- a/arch/sparc/include/asm/page_32.h
+++ b/arch/sparc/include/asm/page_32.h
@@ -8,11 +8,8 @@
#ifndef _SPARC_PAGE_H
#define _SPARC_PAGE_H
-#ifdef CONFIG_SUN4
-#define PAGE_SHIFT 13
-#else
#define PAGE_SHIFT 12
-#endif
+
#ifndef __ASSEMBLY__
/* I have my suspicions... -DaveM */
#define PAGE_SIZE (1UL << PAGE_SHIFT)
diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h
index b579b910ef5..4274ed13ddb 100644
--- a/arch/sparc/include/asm/page_64.h
+++ b/arch/sparc/include/asm/page_64.h
@@ -38,6 +38,8 @@
#ifndef __ASSEMBLY__
+#define WANT_PAGE_VIRTUAL
+
extern void _clear_page(void *page);
#define clear_page(X) _clear_page((void *)(X))
struct page;
diff --git a/arch/sparc/include/asm/parport.h b/arch/sparc/include/asm/parport.h
index d9830621c90..dff3f0253aa 100644
--- a/arch/sparc/include/asm/parport.h
+++ b/arch/sparc/include/asm/parport.h
@@ -8,7 +8,7 @@
#include <linux/of_device.h>
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
#include <asm/ns87303.h>
#include <asm/prom.h>
@@ -215,7 +215,7 @@ static int __devexit ecpp_remove(struct of_device *op)
return 0;
}
-static struct of_device_id ecpp_match[] = {
+static const struct of_device_id ecpp_match[] = {
{
.name = "ecpp",
},
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index 0ee949d220c..b41c4c19815 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -3,6 +3,8 @@
#ifdef __KERNEL__
+#include <linux/dma-mapping.h>
+
/* Can be used to override the logic in pci_scan_bus for skipping
* already-configured bus numbers - to be used for buggy BIOSes
* or architectures with incomplete PCI setup by the loader.
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 08237fda887..e0cabe790ec 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -14,11 +14,7 @@
#include <linux/spinlock.h>
#include <linux/swap.h>
#include <asm/types.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
#include <asm/pgtsun4c.h>
-#endif
#include <asm/pgtsrmmu.h>
#include <asm/vac-ops.h>
#include <asm/oplib.h>
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index bb9ec2cce35..b049abf9902 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -770,6 +770,8 @@ extern void sun4v_patch_tlb_handlers(void);
extern unsigned long cmdline_memory_size;
+extern asmlinkage void do_sparc64_fault(struct pt_regs *regs);
+
#endif /* !(__ASSEMBLY__) */
#endif /* !(_SPARC64_PGTABLE_H) */
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index fd55522481c..900d44714f8 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -18,6 +18,7 @@
*/
#include <linux/types.h>
#include <linux/proc_fs.h>
+#include <linux/mutex.h>
#include <asm/atomic.h>
#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
@@ -73,6 +74,7 @@ struct of_irq_controller {
extern struct device_node *of_find_node_by_cpuid(int cpuid);
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
+extern struct mutex of_set_property_mutex;
extern int of_getintprop_default(struct device_node *np,
const char *name,
int def);
@@ -94,6 +96,16 @@ static inline void of_node_put(struct device_node *node)
{
}
+/* These routines are here to provide compatibility with how powerpc
+ * handles IRQ mapping for OF device nodes. We precompute and permanently
+ * register them in the of_device objects, whereas powerpc computes them
+ * on request.
+ */
+extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+}
+
/*
* NB: This is here while we transition from using asm/prom.h
* to linux/of.h
diff --git a/arch/sparc/include/asm/ptrace_64.h b/arch/sparc/include/asm/ptrace_64.h
index 06e4914c13f..3d3e9c161d8 100644
--- a/arch/sparc/include/asm/ptrace_64.h
+++ b/arch/sparc/include/asm/ptrace_64.h
@@ -113,6 +113,8 @@ struct sparc_trapf {
#ifdef __KERNEL__
+#include <linux/threads.h>
+
static inline int pt_regs_trap_type(struct pt_regs *regs)
{
return regs->magic & 0x1ff;
@@ -138,6 +140,7 @@ struct global_reg_snapshot {
struct thread_info *thread;
unsigned long pad1;
};
+extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
#define __ARCH_WANT_COMPAT_SYS_PTRACE
diff --git a/arch/sparc/include/asm/reboot.h b/arch/sparc/include/asm/reboot.h
deleted file mode 100644
index 3f3f43f5be5..00000000000
--- a/arch/sparc/include/asm/reboot.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC64_REBOOT_H
-#define _SPARC64_REBOOT_H
-
-extern void machine_alt_power_off(void);
-
-#endif /* _SPARC64_REBOOT_H */
diff --git a/arch/sparc/include/asm/rtc.h b/arch/sparc/include/asm/rtc.h
deleted file mode 100644
index f9ecb1fe2ec..00000000000
--- a/arch/sparc/include/asm/rtc.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * rtc.h: Definitions for access to the Mostek real time clock
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _RTC_H
-#define _RTC_H
-
-#include <linux/ioctl.h>
-
-struct rtc_time
-{
- int sec; /* Seconds (0-59) */
- int min; /* Minutes (0-59) */
- int hour; /* Hour (0-23) */
- int dow; /* Day of the week (1-7) */
- int dom; /* Day of the month (1-31) */
- int month; /* Month of year (1-12) */
- int year; /* Year (0-99) */
-};
-
-#define RTCGET _IOR('p', 20, struct rtc_time)
-#define RTCSET _IOW('p', 21, struct rtc_time)
-
-#endif
diff --git a/arch/sparc/include/asm/sbus.h b/arch/sparc/include/asm/sbus.h
deleted file mode 100644
index f82481ab44d..00000000000
--- a/arch/sparc/include/asm/sbus.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_SBUS_H
-#define ___ASM_SPARC_SBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/sbus_64.h>
-#else
-#include <asm/sbus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/sbus_32.h b/arch/sparc/include/asm/sbus_32.h
deleted file mode 100644
index a7b4fa21931..00000000000
--- a/arch/sparc/include/asm/sbus_32.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * sbus.h: Defines for the Sun SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_SBUS_H
-#define _SPARC_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree. SBus devices are described in two different ways. You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR 0xf8000000
-#define SBUS_OFF_MASK 0x01ffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
- return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
- return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
- struct of_device ofdev;
- struct sbus_bus *bus;
- struct sbus_dev *next;
- struct sbus_dev *child;
- struct sbus_dev *parent;
- int prom_node;
- char prom_name[64];
- int slot;
-
- struct resource resource[PROMREG_MAX];
-
- struct linux_prom_registers reg_addrs[PROMREG_MAX];
- int num_registers;
-
- struct linux_prom_ranges device_ranges[PROMREG_MAX];
- int num_device_ranges;
-
- unsigned int irqs[4];
- int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
- struct of_device ofdev;
- struct sbus_dev *devices; /* Link to devices on this SBus */
- struct sbus_bus *next; /* next SBus, if more than one SBus */
- int prom_node; /* PROM device tree node for this SBus */
- char prom_name[64]; /* Usually "sbus" or "sbi" */
- int clock_freq;
-
- struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
- int num_sbus_ranges;
-
- int devid;
- int board;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-static inline int
-sbus_is_slave(struct sbus_dev *dev)
-{
- /* XXX Have to write this for sun4c's */
- return 0;
-}
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
- for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
- for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
- for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
- for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */
-#define sbus_can_burst64(sdev) (0) /* actually, sparc_cpu_model==sun4d */
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-/* These yield IOMMU mappings in consistent mode. */
-extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
-extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32);
-void prom_adjust_ranges(struct linux_prom_ranges *, int,
- struct linux_prom_ranges *, int);
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE DMA_FROM_DEVICE
-#define SBUS_DMA_NONE DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
-extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
-extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
-extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
-extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Eric Brower (ebrower@usa.net)
- * Translate SBus interrupt levels to ino values--
- * this is used when converting sbus "interrupts" OBP
- * node values to "intr" node values, and is platform
- * dependent. If only we could call OBP with
- * "sbus-intr>cpu (sbint -- ino)" from kernel...
- * See .../drivers/sbus/sbus.c for details.
- */
-BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
-#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC_SBUS_H) */
diff --git a/arch/sparc/include/asm/sbus_64.h b/arch/sparc/include/asm/sbus_64.h
deleted file mode 100644
index b606c14343f..00000000000
--- a/arch/sparc/include/asm/sbus_64.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* sbus.h: Defines for the Sun SBus.
- *
- * Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _SPARC64_SBUS_H
-#define _SPARC64_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/iommu.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree. SBus devices are described in two different ways. You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR 0x00000000
-#define SBUS_OFF_MASK 0x0fffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
- return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
- return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
- struct of_device ofdev;
- struct sbus_bus *bus;
- struct sbus_dev *next;
- struct sbus_dev *child;
- struct sbus_dev *parent;
- int prom_node;
- char prom_name[64];
- int slot;
-
- struct resource resource[PROMREG_MAX];
-
- struct linux_prom_registers reg_addrs[PROMREG_MAX];
- int num_registers;
-
- struct linux_prom_ranges device_ranges[PROMREG_MAX];
- int num_device_ranges;
-
- unsigned int irqs[4];
- int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
- struct of_device ofdev;
- struct sbus_dev *devices; /* Tree of SBUS devices */
- struct sbus_bus *next; /* Next SBUS in system */
- int prom_node; /* OBP node of SBUS */
- char prom_name[64]; /* Usually "sbus" or "sbi" */
- int clock_freq;
-
- struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
- int num_sbus_ranges;
-
- int portid;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
- for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
- for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
- for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
- for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev) (1)
-#define sbus_can_burst64(sdev) (1)
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size,
- dma_addr_t *dma_handle)
-{
- return dma_alloc_coherent(&sdev->ofdev.dev, size,
- dma_handle, GFP_ATOMIC);
-}
-
-static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle);
-}
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE DMA_FROM_DEVICE
-#define SBUS_DMA_NONE DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr,
- size_t size, int direction)
-{
- return dma_map_single(&sdev->ofdev.dev, ptr, size,
- (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_single(struct sbus_dev *sdev,
- dma_addr_t dma_addr, size_t size,
- int direction)
-{
- dma_unmap_single(&sdev->ofdev.dev, dma_addr, size,
- (enum dma_data_direction) direction);
-}
-
-static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg,
- int nents, int direction)
-{
- return dma_map_sg(&sdev->ofdev.dev, sg, nents,
- (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg,
- int nents, int direction)
-{
- dma_unmap_sg(&sdev->ofdev.dev, sg, nents,
- (enum dma_data_direction) direction);
-}
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size,
- (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-
-static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- /* No flushing needed to sync cpu writes to the device. */
-}
-
-static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev,
- struct scatterlist *sg,
- int nents, int direction)
-{
- dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents,
- (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-
-static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev,
- struct scatterlist *sg,
- int nents, int direction)
-{
- /* No flushing needed to sync cpu writes to the device. */
-}
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC64_SBUS_H) */
diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h
new file mode 100644
index 00000000000..f90d61c2805
--- /dev/null
+++ b/arch/sparc/include/asm/serial.h
@@ -0,0 +1,6 @@
+#ifndef __SPARC_SERIAL_H
+#define __SPARC_SERIAL_H
+
+#define BASE_BAUD ( 1843200 / 16 )
+
+#endif /* __SPARC_SERIAL_H */
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index de2249b267c..bf2d532593e 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -6,8 +6,6 @@
#ifndef __SPARC_SPINLOCK_H
#define __SPARC_SPINLOCK_H
-#include <linux/threads.h> /* For NR_CPUS */
-
#ifndef __ASSEMBLY__
#include <asm/psr.h>
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 0006fe9f8c7..120cfe4577c 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -6,8 +6,6 @@
#ifndef __SPARC64_SPINLOCK_H
#define __SPARC64_SPINLOCK_H
-#include <linux/threads.h> /* For NR_CPUS */
-
#ifndef __ASSEMBLY__
/* To get debugging spinlocks which detect and catch
diff --git a/arch/sparc/include/asm/sstate.h b/arch/sparc/include/asm/sstate.h
deleted file mode 100644
index a7c35dbcb28..00000000000
--- a/arch/sparc/include/asm/sstate.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _SPARC64_SSTATE_H
-#define _SPARC64_SSTATE_H
-
-extern void sstate_booting(void);
-extern void sstate_running(void);
-extern void sstate_halt(void);
-extern void sstate_poweroff(void);
-extern void sstate_panic(void);
-extern void sstate_reboot(void);
-
-extern void sun4v_sstate_init(void);
-
-#endif /* _SPARC64_SSTATE_H */
diff --git a/arch/sparc/include/asm/starfire.h b/arch/sparc/include/asm/starfire.h
index 07bafd31e33..d56ce60a599 100644
--- a/arch/sparc/include/asm/starfire.h
+++ b/arch/sparc/include/asm/starfire.h
@@ -12,7 +12,6 @@
extern int this_is_starfire;
extern void check_if_starfire(void);
-extern void starfire_cpu_setup(void);
extern int starfire_hard_smp_processor_id(void);
extern void starfire_hookup(int);
extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
diff --git a/arch/sparc/include/asm/statfs.h b/arch/sparc/include/asm/statfs.h
index 5e937a73743..55e607ad461 100644
--- a/arch/sparc/include/asm/statfs.h
+++ b/arch/sparc/include/asm/statfs.h
@@ -1,8 +1,6 @@
#ifndef ___ASM_SPARC_STATFS_H
#define ___ASM_SPARC_STATFS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/statfs_64.h>
-#else
-#include <asm/statfs_32.h>
-#endif
+
+#include <asm-generic/statfs.h>
+
#endif
diff --git a/arch/sparc/include/asm/statfs_32.h b/arch/sparc/include/asm/statfs_32.h
deleted file mode 100644
index 304520fa886..00000000000
--- a/arch/sparc/include/asm/statfs_32.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC_STATFS_H
-#define _SPARC_STATFS_H
-
-#include <asm-generic/statfs.h>
-
-#endif
diff --git a/arch/sparc/include/asm/statfs_64.h b/arch/sparc/include/asm/statfs_64.h
deleted file mode 100644
index 79b3c890a5f..00000000000
--- a/arch/sparc/include/asm/statfs_64.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _SPARC64_STATFS_H
-#define _SPARC64_STATFS_H
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t fsid_t;
-
-#endif
-
-struct statfs {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-
-struct statfs64 {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-
-struct compat_statfs64 {
- __u32 f_type;
- __u32 f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-};
-
-#endif
diff --git a/arch/sparc/include/asm/sun4paddr.h b/arch/sparc/include/asm/sun4paddr.h
deleted file mode 100644
index d52985f19f4..00000000000
--- a/arch/sparc/include/asm/sun4paddr.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * sun4paddr.h: Various physical addresses on sun4 machines
- *
- * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
- * Copyright (C) 1998 Chris Davis (cdavis@cois.on.ca)
- *
- * Now supports more sun4's
- */
-
-#ifndef _SPARC_SUN4PADDR_H
-#define _SPARC_SUN4PADDR_H
-
-#define SUN4_IE_PHYSADDR 0xf5000000
-#define SUN4_UNUSED_PHYSADDR 0
-
-/* these work for me */
-#define SUN4_200_MEMREG_PHYSADDR 0xf4000000
-#define SUN4_200_CLOCK_PHYSADDR 0xf3000000
-#define SUN4_200_BWTWO_PHYSADDR 0xfd000000
-#define SUN4_200_ETH_PHYSADDR 0xf6000000
-#define SUN4_200_SI_PHYSADDR 0xff200000
-
-/* these were here before */
-#define SUN4_300_MEMREG_PHYSADDR 0xf4000000
-#define SUN4_300_CLOCK_PHYSADDR 0xf2000000
-#define SUN4_300_TIMER_PHYSADDR 0xef000000
-#define SUN4_300_ETH_PHYSADDR 0xf9000000
-#define SUN4_300_BWTWO_PHYSADDR 0xfb400000
-#define SUN4_300_DMA_PHYSADDR 0xfa001000
-#define SUN4_300_ESP_PHYSADDR 0xfa000000
-
-/* Are these right? */
-#define SUN4_400_MEMREG_PHYSADDR 0xf4000000
-#define SUN4_400_CLOCK_PHYSADDR 0xf2000000
-#define SUN4_400_TIMER_PHYSADDR 0xef000000
-#define SUN4_400_ETH_PHYSADDR 0xf9000000
-#define SUN4_400_BWTWO_PHYSADDR 0xfb400000
-#define SUN4_400_DMA_PHYSADDR 0xfa001000
-#define SUN4_400_ESP_PHYSADDR 0xfa000000
-
-/*
- these are the actual values set and used in the code. Unused items set
- to SUN_UNUSED_PHYSADDR
- */
-
-extern int sun4_memreg_physaddr; /* memory register (ecc?) */
-extern int sun4_clock_physaddr; /* system clock */
-extern int sun4_timer_physaddr; /* timer, where applicable */
-extern int sun4_eth_physaddr; /* onboard ethernet (ie/le) */
-extern int sun4_si_physaddr; /* sun3 scsi adapter */
-extern int sun4_bwtwo_physaddr; /* onboard bw2 */
-extern int sun4_dma_physaddr; /* scsi dma */
-extern int sun4_esp_physaddr; /* esp scsi */
-extern int sun4_ie_physaddr; /* interrupt enable */
-
-#endif /* !(_SPARC_SUN4PADDR_H) */
diff --git a/arch/sparc/include/asm/sun4prom.h b/arch/sparc/include/asm/sun4prom.h
deleted file mode 100644
index 9c8b4cbf629..00000000000
--- a/arch/sparc/include/asm/sun4prom.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * sun4prom.h -- interface to sun4 PROM monitor. We don't use most of this,
- * so most of these are just placeholders.
- */
-
-#ifndef _SUN4PROM_H_
-#define _SUN4PROM_H_
-
-/*
- * Although this looks similar to an romvec for a OpenProm machine, it is
- * actually closer to what was used in the Sun2 and Sun3.
- *
- * V2 entries exist only in version 2 PROMs and later, V3 in version 3 and later.
- *
- * Many of the function prototypes are guesses. Some are certainly wrong.
- * Use with care.
- */
-
-typedef struct {
- char *initSP; /* Initial system stack ptr */
- void (*startmon)(void); /* Initial PC for hardware */
- int *diagberr; /* Bus err handler for diags */
- struct linux_arguments_v0 **bootParam; /* Info for bootstrapped pgm */
- unsigned int *memorysize; /* Usable memory in bytes */
- unsigned char (*getchar)(void); /* Get char from input device */
- void (*putchar)(char); /* Put char to output device */
- int (*mayget)(void); /* Maybe get char, or -1 */
- int (*mayput)(int); /* Maybe put char, or -1 */
- unsigned char *echo; /* Should getchar echo? */
- unsigned char *insource; /* Input source selector */
- unsigned char *outsink; /* Output sink selector */
- int (*getkey)(void); /* Get next key if one exists */
- void (*initgetkey)(void); /* Initialize get key */
- unsigned int *translation; /* Kbd translation selector */
- unsigned char *keybid; /* Keyboard ID byte */
- int *screen_x; /* V2: Screen x pos (r/o) */
- int *screen_y; /* V2: Screen y pos (r/o) */
- struct keybuf *keybuf; /* Up/down keycode buffer */
- char *monid; /* Monitor version ID */
- void (*fbwritechar)(char); /* Write a character to FB */
- int *fbAddr; /* Address of frame buffer */
- char **font; /* Font table for FB */
- void (*fbwritestr)(char *); /* Write string to FB */
- void (*reboot)(char *); /* e.g. reboot("sd()vmlinux") */
- unsigned char *linebuf; /* The line input buffer */
- unsigned char **lineptr; /* Cur pointer into linebuf */
- int *linesize; /* length of line in linebuf */
- void (*getline)(char *); /* Get line from user */
- unsigned char (*getnextchar)(void); /* Get next char from linebuf */
- unsigned char (*peeknextchar)(void); /* Peek at next char */
- int *fbthere; /* =1 if frame buffer there */
- int (*getnum)(void); /* Grab hex num from line */
- int (*printf)(char *, ...); /* See prom_printf() instead */
- void (*printhex)(int); /* Format N digits in hex */
- unsigned char *leds; /* RAM copy of LED register */
- void (*setLEDs)(unsigned char *); /* Sets LED's and RAM copy */
- void (*NMIaddr)(void *); /* Addr for level 7 vector */
- void (*abortentry)(void); /* Entry for keyboard abort */
- int *nmiclock; /* Counts up in msec */
- int *FBtype; /* Frame buffer type */
- unsigned int romvecversion; /* Version number for this romvec */
- struct globram *globram; /* monitor global variables ??? */
- void * kbdaddr; /* Addr of keyboard in use */
- int *keyrinit; /* ms before kbd repeat */
- unsigned char *keyrtick; /* ms between repetitions */
- unsigned int *memoryavail; /* V1: Main mem usable size */
- long *resetaddr; /* where to jump on a reset */
- long *resetmap; /* pgmap entry for resetaddr */
- void (*exittomon)(void); /* Exit from user program */
- unsigned char **memorybitmap; /* V1: &{0 or &bits} */
- void (*setcxsegmap)(int ctxt, char *va, int pmeg); /* Set seg in any context */
- void (**vector_cmd)(void *); /* V2: Handler for 'v' cmd */
- unsigned long *expectedtrapsig; /* V3: Location of the expected trap signal */
- unsigned long *trapvectorbasetable; /* V3: Address of the trap vector table */
- int unused1;
- int unused2;
- int unused3;
- int unused4;
-} linux_sun4_romvec;
-
-extern linux_sun4_romvec *sun4_romvec;
-
-#endif /* _SUN4PROM_H_ */
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h
index b4b024445fc..8623fc48fe2 100644
--- a/arch/sparc/include/asm/system_32.h
+++ b/arch/sparc/include/asm/system_32.h
@@ -34,13 +34,7 @@ enum sparc_cpu {
extern enum sparc_cpu sparc_cpu_model;
-#ifndef CONFIG_SUN4
-#define ARCH_SUN4C_SUN4 (sparc_cpu_model==sun4c)
-#define ARCH_SUN4 0
-#else
-#define ARCH_SUN4C_SUN4 1
-#define ARCH_SUN4 1
-#endif
+#define ARCH_SUN4C (sparc_cpu_model==sun4c)
#define SUN4M_NCPUS 4 /* Architectural limit of sun4m. */
@@ -55,6 +49,7 @@ extern unsigned long empty_zero_page;
extern void sun_do_break(void);
extern int serial_console;
extern int stop_a_enabled;
+extern int scons_pwroff;
static inline int con_is_present(void)
{
diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h
index db9e742a406..8759f2a1b83 100644
--- a/arch/sparc/include/asm/system_64.h
+++ b/arch/sparc/include/asm/system_64.h
@@ -26,9 +26,8 @@ enum sparc_cpu {
#define sparc_cpu_model sun4u
-/* This cannot ever be a sun4c nor sun4 :) That's just history. */
-#define ARCH_SUN4C_SUN4 0
-#define ARCH_SUN4 0
+/* This cannot ever be a sun4c :) That's just history. */
+#define ARCH_SUN4C 0
extern char reboot_command[];
@@ -118,6 +117,7 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
extern void sun_do_break(void);
extern int stop_a_enabled;
+extern int scons_pwroff;
extern void fault_in_user_windows(void);
extern void synchronize_user_stack(void);
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index cbb892d0dff..29899fd5b1b 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -80,11 +80,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
/*
* thread information allocation
*/
-#if PAGE_SHIFT == 13
-#define THREAD_INFO_ORDER 0
-#else /* PAGE_SHIFT */
#define THREAD_INFO_ORDER 1
-#endif
#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h
index 361e53898dd..2ec030ef381 100644
--- a/arch/sparc/include/asm/timer_32.h
+++ b/arch/sparc/include/asm/timer_32.h
@@ -9,96 +9,9 @@
#define _SPARC_TIMER_H
#include <asm/system.h> /* For SUN4M_NCPUS */
-#include <asm/sun4paddr.h>
#include <asm/btfixup.h>
-/* Timer structures. The interrupt timer has two properties which
- * are the counter (which is handled in do_timer in sched.c) and the limit.
- * This limit is where the timer's counter 'wraps' around. Oddly enough,
- * the sun4c timer when it hits the limit wraps back to 1 and not zero
- * thus when calculating the value at which it will fire a microsecond you
- * must adjust by one. Thanks SUN for designing such great hardware ;(
- */
-
-/* Note that I am only going to use the timer that interrupts at
- * Sparc IRQ 10. There is another one available that can fire at
- * IRQ 14. Currently it is left untouched, we keep the PROM's limit
- * register value and let the prom take these interrupts. This allows
- * L1-A to work.
- */
-
-struct sun4c_timer_info {
- __volatile__ unsigned int cur_count10;
- __volatile__ unsigned int timer_limit10;
- __volatile__ unsigned int cur_count14;
- __volatile__ unsigned int timer_limit14;
-};
-
-#define SUN4C_TIMER_PHYSADDR 0xf3000000
-#ifdef CONFIG_SUN4
-#define SUN_TIMER_PHYSADDR SUN4_300_TIMER_PHYSADDR
-#else
-#define SUN_TIMER_PHYSADDR SUN4C_TIMER_PHYSADDR
-#endif
-
-/* A sun4m has two blocks of registers which are probably of the same
- * structure. LSI Logic's L64851 is told to _decrement_ from the limit
- * value. Aurora behaves similarly but its limit value is compacted in
- * other fashion (it's wider). Documented fields are defined here.
- */
-
-/* As with the interrupt register, we have two classes of timer registers
- * which are per-cpu and master. Per-cpu timers only hit that cpu and are
- * only level 14 ticks, master timer hits all cpus and is level 10.
- */
-
-#define SUN4M_PRM_CNT_L 0x80000000
-#define SUN4M_PRM_CNT_LVALUE 0x7FFFFC00
-
-struct sun4m_timer_percpu_info {
- __volatile__ unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
- __volatile__ unsigned int l14_cur_count;
-
- /* This register appears to be write only and/or inaccessible
- * on Uni-Processor sun4m machines.
- */
- __volatile__ unsigned int l14_limit_noclear; /* Data access error is here */
-
- __volatile__ unsigned int cntrl; /* =1 after POST on Aurora */
- __volatile__ unsigned char space[PAGE_SIZE - 16];
-};
-
-struct sun4m_timer_regs {
- struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
- volatile unsigned int l10_timer_limit;
- volatile unsigned int l10_cur_count;
-
- /* Again, this appears to be write only and/or inaccessible
- * on uni-processor sun4m machines.
- */
- volatile unsigned int l10_limit_noclear;
-
- /* This register too, it must be magic. */
- volatile unsigned int foobar;
-
- volatile unsigned int cfg; /* equals zero at boot time... */
-};
-
-#define SUN4D_PRM_CNT_L 0x80000000
-#define SUN4D_PRM_CNT_LVALUE 0x7FFFFC00
-
-struct sun4d_timer_regs {
- volatile unsigned int l10_timer_limit;
- volatile unsigned int l10_cur_countx;
- volatile unsigned int l10_limit_noclear;
- volatile unsigned int ctrl;
- volatile unsigned int l10_cur_count;
-};
-
-extern struct sun4d_timer_regs *sun4d_timers;
-
extern __volatile__ unsigned int *master_l10_counter;
-extern __volatile__ unsigned int *master_l10_limit;
/* FIXME: Make do_[gs]ettimeofday btfixup calls */
BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
diff --git a/arch/sparc/include/asm/vac-ops.h b/arch/sparc/include/asm/vac-ops.h
index d10527611f1..a63e88ef042 100644
--- a/arch/sparc/include/asm/vac-ops.h
+++ b/arch/sparc/include/asm/vac-ops.h
@@ -76,11 +76,7 @@
* cacheable bit in the pte's of all such pages.
*/
-#ifdef CONFIG_SUN4
-#define S4CVAC_BADBITS 0x0001e000
-#else
#define S4CVAC_BADBITS 0x0000f000
-#endif
/* The following is true if vaddr1 and vaddr2 would cause
* a 'bad alias'.
@@ -94,10 +90,7 @@
*/
struct sun4c_vac_props {
unsigned int num_bytes; /* Size of the cache */
- unsigned int num_lines; /* Number of cache lines */
unsigned int do_hwflushes; /* Hardware flushing available? */
- enum { VAC_NONE, VAC_WRITE_THROUGH,
- VAC_WRITE_BACK } type; /* What type of VAC? */
unsigned int linesize; /* Size of each line in bytes */
unsigned int log2lsize; /* log2(linesize) */
unsigned int on; /* VAC is enabled */
diff --git a/arch/sparc/include/asm/vfc_ioctls.h b/arch/sparc/include/asm/vfc_ioctls.h
deleted file mode 100644
index af8b69007b2..00000000000
--- a/arch/sparc/include/asm/vfc_ioctls.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 1996 by Manish Vachharajani */
-
-#ifndef _LINUX_VFC_IOCTLS_H_
-#define _LINUX_VFC_IOCTLS_H_
-
- /* IOCTLs */
-#define VFC_IOCTL(a) (('j' << 8) | a)
-#define VFCGCTRL (VFC_IOCTL (0)) /* get vfc attributes */
-#define VFCSCTRL (VFC_IOCTL (1)) /* set vfc attributes */
-#define VFCGVID (VFC_IOCTL (2)) /* get video decoder attributes */
-#define VFCSVID (VFC_IOCTL (3)) /* set video decoder attributes */
-#define VFCHUE (VFC_IOCTL (4)) /* set hue */
-#define VFCPORTCHG (VFC_IOCTL (5)) /* change port */
-#define VFCRDINFO (VFC_IOCTL (6)) /* read info */
-
- /* Options for setting the vfc attributes and status */
-#define MEMPRST 0x1 /* reset FIFO ptr. */
-#define CAPTRCMD 0x2 /* start capture and wait */
-#define DIAGMODE 0x3 /* diag mode */
-#define NORMMODE 0x4 /* normal mode */
-#define CAPTRSTR 0x5 /* start capture */
-#define CAPTRWAIT 0x6 /* wait for capture to finish */
-
-
- /* Options for the decoder */
-#define STD_NTSC 0x1 /* NTSC mode */
-#define STD_PAL 0x2 /* PAL mode */
-#define COLOR_ON 0x3 /* force color ON */
-#define MONO 0x4 /* force color OFF */
-
- /* Values returned by ioctl 2 */
-
-#define NO_LOCK 1
-#define NTSC_COLOR 2
-#define NTSC_NOCOLOR 3
-#define PAL_COLOR 4
-#define PAL_NOCOLOR 5
-
-/* Not too sure what this does yet */
- /* Options for setting Field number */
-#define ODD_FIELD 0x1
-#define EVEN_FIELD 0x0
-#define ACTIVE_ONLY 0x2
-#define NON_ACTIVE 0x0
-
-/* Debug options */
-#define VFC_I2C_SEND 0
-#define VFC_I2C_RECV 1
-
-struct vfc_debug_inout
-{
- unsigned long addr;
- unsigned long ret;
- unsigned long len;
- unsigned char __user *buffer;
-};
-
-#endif /* _LINUX_VFC_IOCTLS_H_ */
diff --git a/arch/sparc/include/asm/visasm.h b/arch/sparc/include/asm/visasm.h
index de797b9bf55..39ca301920d 100644
--- a/arch/sparc/include/asm/visasm.h
+++ b/arch/sparc/include/asm/visasm.h
@@ -57,6 +57,7 @@ static inline void save_and_clear_fpu(void) {
" " : : "i" (FPRS_FEF|FPRS_DU) :
"o5", "g1", "g2", "g3", "g7", "cc");
}
+extern int vis_emul(struct pt_regs *, unsigned int);
#endif
#endif /* _SPARC64_ASI_H */
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 6e03a2a7863..2d658209509 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -13,15 +13,13 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
time.o windows.o cpu.o devices.o \
tadpole.o tick14.o ptrace.o \
unaligned.o una_asm.o muldiv.o \
- prom.o of_device.o devres.o
+ prom.o of_device.o devres.o dma.o
devres-y = ../../../kernel/irq/devres.o
obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SUN4) += sun4setup.o
obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_PCI) += ebus.o
obj-$(CONFIG_SUN_PM) += apc.o pmc.o
obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
obj-$(CONFIG_SPARC_LED) += led.o
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
index 5267d48fb2c..4dd1ba752ce 100644
--- a/arch/sparc/kernel/apc.c
+++ b/arch/sparc/kernel/apc.c
@@ -12,9 +12,10 @@
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/auxio.h>
@@ -29,11 +30,10 @@
#define APC_OBPNAME "power-management"
#define APC_DEVNAME "apc"
-volatile static u8 __iomem *regs;
-static int apc_regsize;
+static u8 __iomem *regs;
static int apc_no_idle __initdata = 0;
-#define apc_readb(offs) (sbus_readb(regs+offs))
+#define apc_readb(offs) (sbus_readb(regs+offs))
#define apc_writeb(val, offs) (sbus_writeb(val, regs+offs))
/* Specify "apc=noidle" on the kernel command line to
@@ -69,9 +69,9 @@ static void apc_swift_idle(void)
#endif
}
-static inline void apc_free(void)
+static inline void apc_free(struct of_device *op)
{
- sbus_iounmap(regs, apc_regsize);
+ of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
}
static int apc_open(struct inode *inode, struct file *f)
@@ -153,52 +153,56 @@ static const struct file_operations apc_fops = {
static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
-static int __init apc_probe(void)
+static int __devinit apc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct sbus_bus *sbus = NULL;
- struct sbus_dev *sdev = NULL;
- int iTmp = 0;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
- goto sbus_done;
- }
- }
- }
+ int err;
-sbus_done:
- if (!sdev) {
- return -ENODEV;
- }
-
- apc_regsize = sdev->reg_addrs[0].reg_size;
- regs = sbus_ioremap(&sdev->resource[0], 0,
- apc_regsize, APC_OBPNAME);
- if(!regs) {
+ regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]), APC_OBPNAME);
+ if (!regs) {
printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
return -ENODEV;
}
- iTmp = misc_register(&apc_miscdev);
- if (iTmp != 0) {
+ err = misc_register(&apc_miscdev);
+ if (err) {
printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
- apc_free();
+ apc_free(op);
return -ENODEV;
}
/* Assign power management IDLE handler */
- if(!apc_no_idle)
+ if (!apc_no_idle)
pm_idle = apc_swift_idle;
printk(KERN_INFO "%s: power management initialized%s\n",
- APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+ APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+
return 0;
}
+static struct of_device_id __initdata apc_match[] = {
+ {
+ .name = APC_OBPNAME,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, apc_match);
+
+static struct of_platform_driver apc_driver = {
+ .name = "apc",
+ .match_table = apc_match,
+ .probe = apc_probe,
+};
+
+static int __init apc_init(void)
+{
+ return of_register_driver(&apc_driver, &of_bus_type);
+}
+
/* This driver is not critical to the boot process
* and is easiest to ioremap when SBus is already
* initialized, so we install ourselves thusly:
*/
-__initcall(apc_probe);
-
+__initcall(apc_init);
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
index baf4ed3fb0f..09c857215a5 100644
--- a/arch/sparc/kernel/auxio.c
+++ b/arch/sparc/kernel/auxio.c
@@ -6,6 +6,8 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
@@ -59,7 +61,7 @@ void __init auxio_probe(void)
r.flags = auxregs[0].which_io & 0xF;
r.start = auxregs[0].phys_addr;
r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
- auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
+ auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
/* Fix the address on sun4m and sun4c. */
if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
sparc_cpu_model == sun4c)
@@ -128,7 +130,7 @@ void __init auxio_power_probe(void)
r.flags = regs.which_io & 0xF;
r.start = regs.phys_addr;
r.end = regs.phys_addr + regs.reg_size - 1;
- auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
+ auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
regs.reg_size, "auxpower");
/* Display a quick message on the console. */
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index b240b8863fd..ad656b044b8 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -143,7 +143,7 @@ void __init device_scan(void)
#endif
clock_stop_probe();
- if (ARCH_SUN4C_SUN4)
+ if (ARCH_SUN4C)
sun4c_probe_memerr_reg();
return;
diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c
new file mode 100644
index 00000000000..ebc8403b035
--- /dev/null
+++ b/arch/sparc/kernel/dma.c
@@ -0,0 +1,227 @@
+/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#include "dma.h"
+
+int dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_dma_supported(to_pci_dev(dev), mask);
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#endif
+ return sbus_alloc_consistent(dev, size, dma_handle);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_free_consistent(to_pci_dev(dev), size,
+ cpu_addr, dma_handle);
+ return;
+ }
+#endif
+ sbus_free_consistent(dev, size, cpu_addr, dma_handle);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_map_single(to_pci_dev(dev), cpu_addr,
+ size, (int)direction);
+#endif
+ return sbus_map_single(dev, cpu_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_unmap_single(to_pci_dev(dev), dma_addr,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_unmap_single(dev, dma_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_map_page(to_pci_dev(dev), page, offset,
+ size, (int)direction);
+#endif
+ return sbus_map_single(dev, page_address(page) + offset,
+ size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_unmap_page(to_pci_dev(dev), dma_address,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_unmap_single(dev, dma_address, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+#endif
+ return sbus_map_sg(dev, sg, nents, direction);
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction);
+ return;
+ }
+#endif
+ sbus_unmap_sg(dev, sg, nents, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
+ size, (int)direction);
+ return;
+ }
+#endif
+ sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg,
+ nelems, (int)direction);
+ return;
+ }
+#endif
+ BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type) {
+ pci_dma_sync_sg_for_device(to_pci_dev(dev), sg,
+ nelems, (int)direction);
+ return;
+ }
+#endif
+ BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return (dma_addr == DMA_ERROR_CODE);
+}
+EXPORT_SYMBOL(dma_mapping_error);
+
+int dma_get_cache_alignment(void)
+{
+ return 32;
+}
+EXPORT_SYMBOL(dma_get_cache_alignment);
diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h
new file mode 100644
index 00000000000..f8d8951adb5
--- /dev/null
+++ b/arch/sparc/kernel/dma.h
@@ -0,0 +1,14 @@
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp);
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba);
+dma_addr_t sbus_map_single(struct device *dev, void *va,
+ size_t len, int direction);
+void sbus_unmap_single(struct device *dev, dma_addr_t ba,
+ size_t n, int direction);
+int sbus_map_sg(struct device *dev, struct scatterlist *sg,
+ int n, int direction);
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int n, int direction);
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
+ size_t size, int direction);
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba,
+ size_t size, int direction);
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
deleted file mode 100644
index 97294232259..00000000000
--- a/arch/sparc/kernel/ebus.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * ebus.c: PCI to EBus bridge device.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- * Fixes for different platforms by Pete Zaitcev.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-
-struct linux_ebus *ebus_chain = NULL;
-
-/* We are together with pcic.c under CONFIG_PCI. */
-extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
-
-/*
- * IRQ Blacklist
- * Here we list PROMs and systems that are known to supply crap as IRQ numbers.
- */
-struct ebus_device_irq {
- char *name;
- unsigned int pin;
-};
-
-struct ebus_system_entry {
- char *esname;
- struct ebus_device_irq *ipt;
-};
-
-static struct ebus_device_irq je1_1[] = {
- { "8042", 3 },
- { "SUNW,CS4231", 0 },
- { "parallel", 0 },
- { "se", 2 },
- { NULL, 0 }
-};
-
-/*
- * Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32).
- * Blacklist the sucker... Note that Gleb's system will work.
- */
-static struct ebus_system_entry ebus_blacklist[] = {
- { "SUNW,JavaEngine1", je1_1 },
- { NULL, NULL }
-};
-
-static struct ebus_device_irq *ebus_blackp = NULL;
-
-/*
- */
-static inline unsigned long ebus_alloc(size_t size)
-{
- return (unsigned long)kmalloc(size, GFP_ATOMIC);
-}
-
-/*
- */
-static int __init ebus_blacklist_irq(const char *name)
-{
- struct ebus_device_irq *dp;
-
- if ((dp = ebus_blackp) != NULL) {
- for (; dp->name != NULL; dp++) {
- if (strcmp(name, dp->name) == 0) {
- return pcic_pin_to_irq(dp->pin, name);
- }
- }
- }
- return 0;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
- struct linux_ebus_child *dev)
-{
- const int *regs;
- const int *irqs;
- int i, len;
-
- dev->prom_node = dp;
- regs = of_get_property(dp, "reg", &len);
- if (!regs)
- len = 0;
- dev->num_addrs = len / sizeof(regs[0]);
-
- for (i = 0; i < dev->num_addrs; i++) {
- if (regs[i] >= dev->parent->num_addrs) {
- prom_printf("UGH: property for %s was %d, need < %d\n",
- dev->prom_node->name, len,
- dev->parent->num_addrs);
- panic(__func__);
- }
-
- /* XXX resource */
- dev->resource[i].start =
- dev->parent->resource[regs[i]].start;
- }
-
- for (i = 0; i < PROMINTR_MAX; i++)
- dev->irqs[i] = PCI_IRQ_NONE;
-
- if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
- dev->num_irqs = 1;
- } else {
- irqs = of_get_property(dp, "interrupts", &len);
- if (!irqs) {
- dev->num_irqs = 0;
- dev->irqs[0] = 0;
- if (dev->parent->num_irqs != 0) {
- dev->num_irqs = 1;
- dev->irqs[0] = dev->parent->irqs[0];
- }
- } else {
- dev->num_irqs = len / sizeof(irqs[0]);
- if (irqs[0] == 0 || irqs[0] >= 8) {
- /*
- * XXX Zero is a valid pin number...
- * This works as long as Ebus is not wired
- * to INTA#.
- */
- printk("EBUS: %s got bad irq %d from PROM\n",
- dev->prom_node->name, irqs[0]);
- dev->num_irqs = 0;
- dev->irqs[0] = 0;
- } else {
- dev->irqs[0] =
- pcic_pin_to_irq(irqs[0],
- dev->prom_node->name);
- }
- }
- }
-}
-
-static void __init fill_ebus_device(struct device_node *dp,
- struct linux_ebus_device *dev)
-{
- const struct linux_prom_registers *regs;
- struct linux_ebus_child *child;
- struct dev_archdata *sd;
- const int *irqs;
- int i, n, len;
- unsigned long baseaddr;
-
- dev->prom_node = dp;
-
- regs = of_get_property(dp, "reg", &len);
- if (!regs)
- len = 0;
- if (len % sizeof(struct linux_prom_registers)) {
- prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
- dev->prom_node->name, len,
- (int)sizeof(struct linux_prom_registers));
- panic(__func__);
- }
- dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
- for (i = 0; i < dev->num_addrs; i++) {
- /*
- * XXX Collect JE-1 PROM
- *
- * Example - JS-E with 3.11:
- * /ebus
- * regs
- * 0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,
- * 0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,
- * 0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,
- * ranges
- * 0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,
- * 0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,
- * /ebus/8042
- * regs
- * 0x00000001, 0x00300060, 0x00000008,
- * 0x00000001, 0x00300060, 0x00000008,
- */
- n = regs[i].which_io;
- if (n >= 4) {
- /* XXX This is copied from old JE-1 by Gleb. */
- n = (regs[i].which_io - 0x10) >> 2;
- } else {
- ;
- }
-
-/*
- * XXX Now as we have regions, why don't we make an on-demand allocation...
- */
- dev->resource[i].start = 0;
- if ((baseaddr = dev->bus->self->resource[n].start +
- regs[i].phys_addr) != 0) {
- /* dev->resource[i].name = dev->prom_name; */
- if ((baseaddr = (unsigned long) ioremap(baseaddr,
- regs[i].reg_size)) == 0) {
- panic("ebus: unable to remap dev %s",
- dev->prom_node->name);
- }
- }
- dev->resource[i].start = baseaddr; /* XXX Unaligned */
- }
-
- for (i = 0; i < PROMINTR_MAX; i++)
- dev->irqs[i] = PCI_IRQ_NONE;
-
- if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
- dev->num_irqs = 1;
- } else {
- irqs = of_get_property(dp, "interrupts", &len);
- if (!irqs) {
- dev->num_irqs = 0;
- if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
- dev->num_irqs = 1;
-/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
- }
- } else {
- dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
- if (irqs[0] == 0 || irqs[0] >= 8) {
- /* See above for the parent. XXX */
- printk("EBUS: %s got bad irq %d from PROM\n",
- dev->prom_node->name, irqs[0]);
- dev->num_irqs = 0;
- dev->irqs[0] = 0;
- } else {
- dev->irqs[0] =
- pcic_pin_to_irq(irqs[0],
- dev->prom_node->name);
- }
- }
- }
-
- sd = &dev->ofdev.dev.archdata;
- sd->prom_node = dp;
- sd->op = &dev->ofdev;
- sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-
- dev->ofdev.node = dp;
- dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
- dev->ofdev.dev.bus = &ebus_bus_type;
- sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
-
- /* Register with core */
- if (of_device_register(&dev->ofdev) != 0)
- printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- dp->path_component_name);
-
- if ((dp = dp->child) != NULL) {
- dev->children = (struct linux_ebus_child *)
- ebus_alloc(sizeof(struct linux_ebus_child));
-
- child = dev->children;
- child->next = NULL;
- child->parent = dev;
- child->bus = dev->bus;
- fill_ebus_child(dp, child);
-
- while ((dp = dp->sibling) != NULL) {
- child->next = (struct linux_ebus_child *)
- ebus_alloc(sizeof(struct linux_ebus_child));
-
- child = child->next;
- child->next = NULL;
- child->parent = dev;
- child->bus = dev->bus;
- fill_ebus_child(dp, child);
- }
- }
-}
-
-void __init ebus_init(void)
-{
- const struct linux_prom_pci_registers *regs;
- struct linux_pbm_info *pbm;
- struct linux_ebus_device *dev;
- struct linux_ebus *ebus;
- struct ebus_system_entry *sp;
- struct pci_dev *pdev;
- struct pcidev_cookie *cookie;
- struct device_node *dp;
- struct resource *p;
- unsigned short pci_command;
- int len, reg, nreg;
- int num_ebus = 0;
-
- dp = of_find_node_by_path("/");
- for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
- if (strcmp(dp->name, sp->esname) == 0) {
- ebus_blackp = sp->ipt;
- break;
- }
- }
-
- pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
- if (!pdev)
- return;
-
- cookie = pdev->sysdata;
- dp = cookie->prom_node;
-
- ebus_chain = ebus = (struct linux_ebus *)
- ebus_alloc(sizeof(struct linux_ebus));
- ebus->next = NULL;
-
- while (dp) {
- struct device_node *nd;
-
- ebus->prom_node = dp;
- ebus->self = pdev;
- ebus->parent = pbm = cookie->pbm;
-
- /* Enable BUS Master. */
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- pci_command |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
- regs = of_get_property(dp, "reg", &len);
- if (!regs) {
- prom_printf("%s: can't find reg property\n",
- __func__);
- prom_halt();
- }
- nreg = len / sizeof(struct linux_prom_pci_registers);
-
- p = &ebus->self->resource[0];
- for (reg = 0; reg < nreg; reg++) {
- if (!(regs[reg].which_io & 0x03000000))
- continue;
-
- (p++)->start = regs[reg].phys_lo;
- }
-
- ebus->ofdev.node = dp;
- ebus->ofdev.dev.parent = &pdev->dev;
- ebus->ofdev.dev.bus = &ebus_bus_type;
- sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
-
- /* Register with core */
- if (of_device_register(&ebus->ofdev) != 0)
- printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- dp->path_component_name);
-
-
- nd = dp->child;
- if (!nd)
- goto next_ebus;
-
- ebus->devices = (struct linux_ebus_device *)
- ebus_alloc(sizeof(struct linux_ebus_device));
-
- dev = ebus->devices;
- dev->next = NULL;
- dev->children = NULL;
- dev->bus = ebus;
- fill_ebus_device(nd, dev);
-
- while ((nd = nd->sibling) != NULL) {
- dev->next = (struct linux_ebus_device *)
- ebus_alloc(sizeof(struct linux_ebus_device));
-
- dev = dev->next;
- dev->next = NULL;
- dev->children = NULL;
- dev->bus = ebus;
- fill_ebus_device(nd, dev);
- }
-
- next_ebus:
- pdev = pci_get_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_EBUS, pdev);
- if (!pdev)
- break;
-
- cookie = pdev->sysdata;
- dp = cookie->prom_node;
-
- ebus->next = (struct linux_ebus *)
- ebus_alloc(sizeof(struct linux_ebus));
- ebus = ebus->next;
- ebus->next = NULL;
- ++num_ebus;
- }
- if (pdev)
- pci_dev_put(pdev);
-}
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index e8cdf715a54..faf9ccd9ef5 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -20,11 +20,7 @@
#include <asm/memreg.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
#include <asm/pgtsun4c.h>
-#endif
#include <asm/winmacro.h>
#include <asm/signal.h>
#include <asm/obio.h>
@@ -276,17 +272,18 @@ smp4m_ticker:
*/
maybe_smp4m_msg:
GET_PROCESSOR4M_ID(o3)
- set sun4m_interrupts, %l5
- ld [%l5], %o5
+ sethi %hi(sun4m_irq_percpu), %l5
+ sll %o3, 2, %o3
+ or %l5, %lo(sun4m_irq_percpu), %o5
sethi %hi(0x40000000), %o2
- sll %o3, 12, %o3
ld [%o5 + %o3], %o1
- andcc %o1, %o2, %g0
+ ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
+ andcc %o3, %o2, %g0
be,a smp4m_ticker
cmp %l7, 14
- st %o2, [%o5 + 0x4]
+ st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000
WRITE_PAUSE
- ld [%o5], %g0
+ ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
@@ -304,16 +301,16 @@ linux_trap_ipi15_sun4m:
SAVE_ALL
sethi %hi(0x80000000), %o2
GET_PROCESSOR4M_ID(o0)
- set sun4m_interrupts, %l5
- ld [%l5], %o5
- sll %o0, 12, %o0
- add %o5, %o0, %o5
- ld [%o5], %o3
+ sethi %hi(sun4m_irq_percpu), %l5
+ or %l5, %lo(sun4m_irq_percpu), %o5
+ sll %o0, 2, %o0
+ ld [%o5 + %o0], %o5
+ ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
andcc %o3, %o2, %g0
be 1f ! Must be an NMI async memory error
- st %o2, [%o5 + 4]
+ st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000
WRITE_PAUSE
- ld [%o5], %g0
+ ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
@@ -327,12 +324,11 @@ linux_trap_ipi15_sun4m:
1:
/* NMI async memory error handling. */
sethi %hi(0x80000000), %l4
- sethi %hi(0x4000), %o3
- sub %o5, %o0, %o5
- add %o5, %o3, %l5
- st %l4, [%l5 + 0xc]
+ sethi %hi(sun4m_irq_global), %o5
+ ld [%o5 + %lo(sun4m_irq_global)], %l5
+ st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000
WRITE_PAUSE
- ld [%l5], %g0
+ ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
@@ -341,9 +337,9 @@ linux_trap_ipi15_sun4m:
WRITE_PAUSE
call sun4m_nmi
nop
- st %l4, [%l5 + 0x8]
+ st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000
WRITE_PAUSE
- ld [%l5], %g0
+ ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE
RESTORE_ALL
@@ -775,11 +771,7 @@ vac_linesize_patch_32: subcc %l7, 32, %l7
* Ugly, but we cant use hardware flushing on the sun4 and we'd require
* two instructions (Anton)
*/
-#ifdef CONFIG_SUN4
-vac_hwflush_patch1_on: nop
-#else
vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7
-#endif
vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
@@ -798,42 +790,10 @@ vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
! %l7 = 1 for textfault
! We want error in %l5, vaddr in %l6
sun4c_fault:
-#ifdef CONFIG_SUN4
- sethi %hi(sun4c_memerr_reg), %l4
- ld [%l4+%lo(sun4c_memerr_reg)], %l4 ! memerr ctrl reg addr
- ld [%l4], %l6 ! memerr ctrl reg
- ld [%l4 + 4], %l5 ! memerr vaddr reg
- andcc %l6, 0x80, %g0 ! check for error type
- st %g0, [%l4 + 4] ! clear the error
- be 0f ! normal error
- sethi %hi(AC_BUS_ERROR), %l4 ! bus err reg addr
-
- call prom_halt ! something weird happened
- ! what exactly did happen?
- ! what should we do here?
-
-0: or %l4, %lo(AC_BUS_ERROR), %l4 ! bus err reg addr
- lduba [%l4] ASI_CONTROL, %l6 ! bus err reg
-
- cmp %l7, 1 ! text fault?
- be 1f ! yes
- nop
-
- ld [%l1], %l4 ! load instruction that caused fault
- srl %l4, 21, %l4
- andcc %l4, 1, %g0 ! store instruction?
-
- be 1f ! no
- sethi %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
- ! %lo(SUN4C_SYNC_BADWRITE) = 0
- or %l4, %l6, %l6 ! set write bit to emulate sun4c
-1:
-#else
sethi %hi(AC_SYNC_ERR), %l4
add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6
lda [%l6] ASI_CONTROL, %l5 ! Address
lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit
-#endif
andn %l5, 0xfff, %l5 ! Encode all info into l7
srl %l6, 14, %l4
@@ -880,12 +840,7 @@ sun4c_fault:
or %l4, %lo(swapper_pg_dir), %l4
sll %l6, 2, %l6
ld [%l4 + %l6], %l4
-#ifdef CONFIG_SUN4
- sethi %hi(PAGE_MASK), %l6
- andcc %l4, %l6, %g0
-#else
andcc %l4, PAGE_MASK, %g0
-#endif
be sun4c_fault_fromuser
lduXa [%l5] ASI_SEGMAP, %l4
@@ -937,11 +892,7 @@ invalid_segment_patch1:
ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr
! Flush segment from the cache.
-#ifdef CONFIG_SUN4
- sethi %hi((128 * 1024)), %l7
-#else
sethi %hi((64 * 1024)), %l7
-#endif
9:
vac_hwflush_patch1:
vac_linesize_patch:
@@ -1029,12 +980,7 @@ invalid_segment_patch2:
or %l4, %lo(swapper_pg_dir), %l4
sll %l3, 2, %l3
ld [%l4 + %l3], %l4
-#ifndef CONFIG_SUN4
and %l4, PAGE_MASK, %l4
-#else
- sethi %hi(PAGE_MASK), %l6
- and %l4, %l6, %l4
-#endif
srl %l5, (PAGE_SHIFT - 2), %l6
and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 50d9a16af79..2d325fd8457 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -63,15 +63,9 @@ cputypvar_sun4m:
.align 4
-#ifndef CONFIG_SUN4
sun4_notsup:
- .asciz "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n"
+ .asciz "Sparc-Linux sun4 support does no longer exist.\n\n"
.align 4
-#else
-sun4cdm_notsup:
- .asciz "Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n"
- .align 4
-#endif
sun4e_notsup:
.asciz "Sparc-Linux sun4e support does not exist\n\n"
@@ -780,15 +774,6 @@ execute_in_high_mem:
nop
found_version:
-#ifdef CONFIG_SUN4
-/* For people who try sun4 kernels, even if Configure.help advises them. */
- ld [%g7 + 0x68], %o1
- set sun4cdm_notsup, %o0
- call %o1
- nop
- b halt_me
- nop
-#endif
/* Get the machine type via the mysterious romvec node operations. */
add %g7, 0x1c, %l1
@@ -1150,15 +1135,6 @@ sun4c_continue_boot:
nop
sun4_init:
-#ifdef CONFIG_SUN4
-/* There, happy now Adrian? */
- set cputypval, %o2 ! Let everyone know we
- set ' ', %o0 ! are a "sun4 " architecture
- stb %o0, [%o2 + 0x4]
-
- b got_prop
- nop
-#else
sethi %hi(SUN4_PROM_VECTOR+0x84), %o1
ld [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
set sun4_notsup, %o0
@@ -1170,7 +1146,7 @@ sun4_init:
nop
1: ba 1b ! Cannot exit into KMON
nop
-#endif
+
no_sun4e_here:
ld [%g7 + 0x68], %o1
set sun4e_notsup, %o0
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
index fc511f3c4c1..223a6582e1e 100644
--- a/arch/sparc/kernel/idprom.c
+++ b/arch/sparc/kernel/idprom.c
@@ -12,10 +12,6 @@
#include <asm/oplib.h>
#include <asm/idprom.h>
#include <asm/machines.h> /* Fun with Sun released architectures. */
-#ifdef CONFIG_SUN4
-#include <asm/sun4paddr.h>
-extern void sun4setup(void);
-#endif
struct idprom *idprom;
static struct idprom idprom_buffer;
@@ -101,7 +97,4 @@ void __init idprom_init(void)
idprom->id_ethaddr[0], idprom->id_ethaddr[1],
idprom->id_ethaddr[2], idprom->id_ethaddr[3],
idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
-#ifdef CONFIG_SUN4
- sun4setup();
-#endif
}
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 2a8a847764d..4f025b36934 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -42,10 +42,13 @@
#include <asm/vaddrs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
-#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
+#include <asm/iommu.h>
+#include <asm/io-unit.h>
+
+#include "dma.h"
#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
@@ -139,15 +142,6 @@ void iounmap(volatile void __iomem *virtual)
}
}
-/*
- */
-void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset,
- unsigned long size, char *name)
-{
- return _sparc_alloc_io(phyres->flags & 0xF,
- phyres->start + offset, size, name);
-}
-
void __iomem *of_ioremap(struct resource *res, unsigned long offset,
unsigned long size, char *name)
{
@@ -164,13 +158,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
EXPORT_SYMBOL(of_iounmap);
/*
- */
-void sbus_iounmap(volatile void __iomem *addr, unsigned long size)
-{
- iounmap(addr);
-}
-
-/*
* Meat of mapping
*/
static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
@@ -246,63 +233,19 @@ static void _sparc_free_io(struct resource *res)
#ifdef CONFIG_SBUS
-void sbus_set_sbus64(struct sbus_dev *sdev, int x)
+void sbus_set_sbus64(struct device *dev, int x)
{
printk("sbus_set_sbus64: unsupported\n");
}
-extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
-void __init sbus_fill_device_irq(struct sbus_dev *sdev)
-{
- struct linux_prom_irqs irqs[PROMINTR_MAX];
- int len;
-
- len = prom_getproperty(sdev->prom_node, "intr",
- (char *)irqs, sizeof(irqs));
- if (len != -1) {
- sdev->num_irqs = len / 8;
- if (sdev->num_irqs == 0) {
- sdev->irqs[0] = 0;
- } else if (sparc_cpu_model == sun4d) {
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] =
- sun4d_build_irq(sdev, irqs[len].pri);
- } else {
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] = irqs[len].pri;
- }
- } else {
- int interrupts[PROMINTR_MAX];
-
- /* No "intr" node found-- check for "interrupts" node.
- * This node contains SBus interrupt levels, not IPLs
- * as in "intr", and no vector values. We convert
- * SBus interrupt levels to PILs (platform specific).
- */
- len = prom_getproperty(sdev->prom_node, "interrupts",
- (char *)interrupts, sizeof(interrupts));
- if (len == -1) {
- sdev->irqs[0] = 0;
- sdev->num_irqs = 0;
- } else {
- sdev->num_irqs = len / sizeof(int);
- for (len = 0; len < sdev->num_irqs; len++) {
- sdev->irqs[len] =
- sbint_to_irq(sdev, interrupts[len]);
- }
- }
- }
-}
-
/*
* Allocate a chunk of memory suitable for DMA.
* Typically devices use them for control blocks.
* CPU may access them without any explicit flushing.
- *
- * XXX Some clever people know that sdev is not used and supply NULL. Watch.
*/
-void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp)
{
+ struct of_device *op = to_of_device(dev);
unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
unsigned long va;
struct resource *res;
@@ -336,13 +279,10 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
* XXX That's where sdev would be used. Currently we load
* all iommu tables with the same translations.
*/
- if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0)
+ if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
goto err_noiommu;
- /* Set the resource name, if known. */
- if (sdev) {
- res->name = sdev->prom_name;
- }
+ res->name = op->node->name;
return (void *)(unsigned long)res->start;
@@ -356,7 +296,7 @@ err_nopages:
return NULL;
}
-void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
{
struct resource *res;
struct page *pgv;
@@ -383,8 +323,8 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
kfree(res);
/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
- pgv = mmu_translate_dvma(ba);
- mmu_unmap_dma_area(ba, n);
+ pgv = virt_to_page(p);
+ mmu_unmap_dma_area(dev, ba, n);
__free_pages(pgv, get_order(n));
}
@@ -394,7 +334,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
* CPU view of this memory may be inconsistent with
* a device view and explicit flushing is necessary.
*/
-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
+dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction)
{
/* XXX why are some lengths signed, others unsigned? */
if (len <= 0) {
@@ -404,17 +344,17 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int dire
if (len > 256*1024) { /* __get_free_pages() limit */
return 0;
}
- return mmu_get_scsi_one(va, len, sdev->bus);
+ return mmu_get_scsi_one(dev, va, len);
}
-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction)
+void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction)
{
- mmu_release_scsi_one(ba, n, sdev->bus);
+ mmu_release_scsi_one(dev, ba, n);
}
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
{
- mmu_get_scsi_sgl(sg, n, sdev->bus);
+ mmu_get_scsi_sgl(dev, sg, n);
/*
* XXX sparc64 can return a partial length here. sun4c should do this
@@ -423,145 +363,28 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direct
return n;
}
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
-{
- mmu_release_scsi_sgl(sg, n, sdev->bus);
-}
-
-/*
- */
-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
-{
-#if 0
- unsigned long va;
- struct resource *res;
-
- /* We do not need the resource, just print a message if invalid. */
- res = _sparc_find_resource(&_sparc_dvma, ba);
- if (res == NULL)
- panic("sbus_dma_sync_single: 0x%x\n", ba);
-
- va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
- /*
- * XXX This bogosity will be fixed with the iommu rewrite coming soon
- * to a kernel near you. - Anton
- */
- /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
-}
-
-void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
{
-#if 0
- unsigned long va;
- struct resource *res;
-
- /* We do not need the resource, just print a message if invalid. */
- res = _sparc_find_resource(&_sparc_dvma, ba);
- if (res == NULL)
- panic("sbus_dma_sync_single: 0x%x\n", ba);
-
- va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
- /*
- * XXX This bogosity will be fixed with the iommu rewrite coming soon
- * to a kernel near you. - Anton
- */
- /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
+ mmu_release_scsi_sgl(dev, sg, n);
}
-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction)
{
- printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");
}
-void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction)
{
- printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
-}
-
-/* Support code for sbus_init(). */
-/*
- * XXX This functions appears to be a distorted version of
- * prom_sbus_ranges_init(), with all sun4d stuff cut away.
- * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
- */
-/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
- int parent_node = pn->node;
-
- if (sparc_cpu_model == sun4d) {
- struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
- int num_iounit_ranges, len;
-
- len = prom_getproperty(parent_node, "ranges",
- (char *) iounit_ranges,
- sizeof (iounit_ranges));
- if (len != -1) {
- num_iounit_ranges =
- (len / sizeof(struct linux_prom_ranges));
- prom_adjust_ranges(sbus->sbus_ranges,
- sbus->num_sbus_ranges,
- iounit_ranges, num_iounit_ranges);
- }
- }
}
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-#ifndef CONFIG_SUN4
- struct device_node *parent = dp->parent;
-
- if (sparc_cpu_model != sun4d &&
- parent != NULL &&
- !strcmp(parent->name, "iommu")) {
- extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
-
- iommu_init(parent->node, sbus);
- }
-
- if (sparc_cpu_model == sun4d) {
- extern void iounit_init(int sbi_node, int iounit_node,
- struct sbus_bus *sbus);
-
- iounit_init(dp->node, parent->node, sbus);
- }
-#endif
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
- if (sparc_cpu_model == sun4d) {
- struct device_node *parent = dp->parent;
-
- sbus->devid = of_getintprop_default(parent, "device-id", 0);
- sbus->board = of_getintprop_default(parent, "board#", 0);
- }
-}
-
-int __init sbus_arch_preinit(void)
+static int __init sparc_register_ioport(void)
{
register_proc_sparc_ioport();
-#ifdef CONFIG_SUN4
- {
- extern void sun4_dvma_init(void);
- sun4_dvma_init();
- }
- return 1;
-#else
return 0;
-#endif
}
-void __init sbus_arch_postinit(void)
-{
- if (sparc_cpu_model == sun4d) {
- extern void sun4d_init_sbi_irq(void);
- sun4d_init_sbi_irq();
- }
-}
+arch_initcall(sparc_register_ioport);
+
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 32ef3ebd0a8..db751388153 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -13,7 +13,6 @@ BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
static inline void __disable_irq(unsigned int irq)
@@ -41,11 +40,6 @@ static inline void clear_clock_irq(void)
BTFIXUP_CALL(clear_clock_irq)();
}
-static inline void clear_profile_irq(int irq)
-{
- BTFIXUP_CALL(clear_profile_irq)(irq);
-}
-
static inline void load_profile_irq(int cpu, int limit)
{
BTFIXUP_CALL(load_profile_irq)(cpu, limit);
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index f58c537446a..0837bd52e28 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -29,15 +29,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
}
EXPORT_SYMBOL(of_find_device_by_node);
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+ struct of_device *op = of_find_device_by_node(node);
+
+ if (!op || index >= op->num_irqs)
+ return 0;
+
+ return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+ struct dev_archdata *bus_sd = &bus->dev.archdata;
+ struct device_node *bus_dp = bus->node;
+ struct device_node *dp;
+
+ for (dp = bus_dp->child; dp; dp = dp->sibling) {
+ struct of_device *op = of_find_device_by_node(dp);
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+ op->dev.archdata.iommu = bus_sd->iommu;
+ op->dev.archdata.stc = bus_sd->stc;
+ op->dev.archdata.host_controller = bus_sd->host_controller;
+ op->dev.archdata.numa_node = bus_sd->numa_node;
+
+ if (dp->child)
+ of_propagate_archdata(op);
+ }
+}
struct bus_type of_platform_bus_type;
EXPORT_SYMBOL(of_platform_bus_type);
@@ -327,6 +350,27 @@ static int __init build_one_resource(struct device_node *parent,
return 1;
}
+static int __init use_1to1_mapping(struct device_node *pp)
+{
+ /* If we have a ranges property in the parent, use it. */
+ if (of_find_property(pp, "ranges", NULL) != NULL)
+ return 0;
+
+ /* Some SBUS devices use intermediate nodes to express
+ * hierarchy within the device itself. These aren't
+ * real bus nodes, and don't have a 'ranges' property.
+ * But, we should still pass the translation work up
+ * to the SBUS itself.
+ */
+ if (!strcmp(pp->name, "dma") ||
+ !strcmp(pp->name, "espdma") ||
+ !strcmp(pp->name, "ledma") ||
+ !strcmp(pp->name, "lebuffer"))
+ return 0;
+
+ return 1;
+}
+
static int of_resource_verbose;
static void __init build_device_resources(struct of_device *op,
@@ -373,10 +417,7 @@ static void __init build_device_resources(struct of_device *op,
flags = bus->get_flags(reg, 0);
- /* If the immediate parent has no ranges property to apply,
- * just use a 1<->1 mapping.
- */
- if (of_find_property(pp, "ranges", NULL) == NULL) {
+ if (use_1to1_mapping(pp)) {
result = of_read_addr(addr, na);
goto build_res;
}
@@ -565,15 +606,6 @@ static int __init of_bus_driver_init(void)
int err;
err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
- if (!err)
- err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
- if (!err)
- err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
if (!err)
scan_of_devices();
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index a6a6f982337..462584e55fb 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -17,8 +17,6 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <asm/ebus.h>
-#include <asm/sbus.h> /* for sanity check... */
#include <asm/swift.h> /* for cache flushing. */
#include <asm/io.h>
@@ -430,7 +428,6 @@ static int __init pcic_init(void)
pcic_pbm_scan_bus(pcic);
- ebus_init();
return 0;
}
@@ -493,10 +490,6 @@ static void pcic_map_pci_device(struct linux_pcic *pcic,
* do ioremap() before accessing PC-style I/O,
* we supply virtual, ready to access address.
*
- * Ebus devices do not come here even if
- * CheerIO makes a similar conversion.
- * See ebus.c for details.
- *
* Note that request_region()
* works for these devices.
*
@@ -677,7 +670,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
}
/*
- * pcic_pin_to_irq() is exported to ebus.c.
+ * pcic_pin_to_irq() is exported to bus probing code
*/
unsigned int
pcic_pin_to_irq(unsigned int pin, const char *name)
@@ -904,11 +897,6 @@ static void pcic_enable_irq(unsigned int irq_nr)
local_irq_restore(flags);
}
-static void pcic_clear_profile_irq(int cpu)
-{
- printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
-}
-
static void pcic_load_profile_irq(int cpu, unsigned int limit)
{
printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
@@ -934,7 +922,6 @@ void __init sun4m_pci_init_IRQ(void)
BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
}
diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c
index 7eca8871ff4..2afcfab4f11 100644
--- a/arch/sparc/kernel/pmc.c
+++ b/arch/sparc/kernel/pmc.c
@@ -8,11 +8,11 @@
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/miscdevice.h>
#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/auxio.h>
@@ -23,17 +23,15 @@
* #define PMC_NO_IDLE
*/
-#define PMC_MINOR MISC_DYNAMIC_MINOR
#define PMC_OBPNAME "SUNW,pmc"
#define PMC_DEVNAME "pmc"
#define PMC_IDLE_REG 0x00
#define PMC_IDLE_ON 0x01
-volatile static u8 __iomem *regs;
-static int pmc_regsize;
+static u8 __iomem *regs;
-#define pmc_readb(offs) (sbus_readb(regs+offs))
+#define pmc_readb(offs) (sbus_readb(regs+offs))
#define pmc_writeb(val, offs) (sbus_writeb(val, regs+offs))
/*
@@ -53,31 +51,11 @@ void pmc_swift_idle(void)
#endif
}
-static inline void pmc_free(void)
+static int __devinit pmc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- sbus_iounmap(regs, pmc_regsize);
-}
-
-static int __init pmc_probe(void)
-{
- struct sbus_bus *sbus = NULL;
- struct sbus_dev *sdev = NULL;
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
- goto sbus_done;
- }
- }
- }
-
-sbus_done:
- if (!sdev) {
- return -ENODEV;
- }
-
- pmc_regsize = sdev->reg_addrs[0].reg_size;
- regs = sbus_ioremap(&sdev->resource[0], 0,
- pmc_regsize, PMC_OBPNAME);
+ regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]), PMC_OBPNAME);
if (!regs) {
printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
return -ENODEV;
@@ -92,8 +70,27 @@ sbus_done:
return 0;
}
+static struct of_device_id __initdata pmc_match[] = {
+ {
+ .name = PMC_OBPNAME,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pmc_match);
+
+static struct of_platform_driver pmc_driver = {
+ .name = "pmc",
+ .match_table = pmc_match,
+ .probe = pmc_probe,
+};
+
+static int __init pmc_init(void)
+{
+ return of_register_driver(&pmc_driver, &of_bus_type);
+}
+
/* This driver is not critical to the boot process
* and is easiest to ioremap when SBus is already
* initialized, so we install ourselves thusly:
*/
-__initcall(pmc_probe);
+__initcall(pmc_init);
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 4bb430940a6..e8c43ffe317 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -75,7 +75,7 @@ void cpu_idle(void)
{
/* endless idle loop with no priority at all */
for (;;) {
- if (ARCH_SUN4C_SUN4) {
+ if (ARCH_SUN4C) {
static int count = HZ;
static unsigned long last_jiffies;
static unsigned long last_faults;
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index cd4fb79aa3a..eee5efcfe50 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -54,6 +54,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
}
EXPORT_SYMBOL(of_getintprop_default);
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
int of_set_property(struct device_node *dp, const char *name, void *val, int len)
{
struct property **prevp;
@@ -77,7 +80,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
void *old_val = prop->value;
int ret;
+ mutex_lock(&of_set_property_mutex);
ret = prom_setprop(dp->node, (char *) name, val, len);
+ mutex_unlock(&of_set_property_mutex);
+
err = -EINVAL;
if (ret >= 0) {
prop->value = new_val;
@@ -436,7 +442,6 @@ static void __init of_console_init(void)
switch (prom_vers) {
case PROM_V0:
- case PROM_SUN4:
skip = 0;
switch (*romvec->pv_stdout) {
case PROMDEV_SCREEN:
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 9e451b21202..24fe3078bd4 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -213,23 +213,25 @@ void __init setup_arch(char **cmdline_p)
/* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs();
strcpy(boot_command_line, *cmdline_p);
+ parse_early_param();
/* Set sparc_cpu_model */
sparc_cpu_model = sun_unknown;
- if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
- if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
- if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
- if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; } /* CP-1200 with PROM 2.30 -E */
- if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
- if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
- if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
-
-#ifdef CONFIG_SUN4
- if (sparc_cpu_model != sun4) {
- prom_printf("This kernel is for Sun4 architecture only.\n");
- prom_halt();
- }
-#endif
+ if (!strcmp(&cputypval,"sun4 "))
+ sparc_cpu_model = sun4;
+ if (!strcmp(&cputypval,"sun4c"))
+ sparc_cpu_model = sun4c;
+ if (!strcmp(&cputypval,"sun4m"))
+ sparc_cpu_model = sun4m;
+ if (!strcmp(&cputypval,"sun4s"))
+ sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
+ if (!strcmp(&cputypval,"sun4d"))
+ sparc_cpu_model = sun4d;
+ if (!strcmp(&cputypval,"sun4e"))
+ sparc_cpu_model = sun4e;
+ if (!strcmp(&cputypval,"sun4u"))
+ sparc_cpu_model = sun4u;
+
printk("ARCH: ");
switch(sparc_cpu_model) {
case sun4:
@@ -263,7 +265,7 @@ void __init setup_arch(char **cmdline_p)
boot_flags_init(*cmdline_p);
idprom_init();
- if (ARCH_SUN4C_SUN4)
+ if (ARCH_SUN4C)
sun4c_probe_vac();
load_mmu();
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index b23cea5ca5d..b0dfff84865 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -38,17 +38,12 @@
#include <asm/idprom.h>
#include <asm/head.h>
#include <asm/smp.h>
-#include <asm/mostek.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
#include <asm/dma.h>
#endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
#include <asm/io-unit.h>
#include <asm/bug.h>
@@ -127,16 +122,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(rtc_lock);
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
#ifdef CONFIG_SUN_AUXIO
EXPORT_SYMBOL(set_auxio);
EXPORT_SYMBOL(get_auxio);
#endif
EXPORT_SYMBOL(io_remap_pfn_range);
- /* P3: iounit_xxx may be needed, sun4d users */
-/* EXPORT_SYMBOL(iounit_map_dma_init); */
-/* EXPORT_SYMBOL(iounit_map_dma_page); */
#ifndef CONFIG_SMP
EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
@@ -153,24 +143,9 @@ EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one));
EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached));
#ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
-EXPORT_SYMBOL(sbus_iounmap);
-EXPORT_SYMBOL(sbus_ioremap);
#endif
#ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
EXPORT_SYMBOL(insb);
EXPORT_SYMBOL(outsb);
EXPORT_SYMBOL(insw);
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 340fc395fe2..5dc8a576948 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -18,6 +18,8 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include "irq.h"
#include <asm/ptrace.h>
@@ -31,15 +33,8 @@
#include <asm/traps.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/sun4paddr.h>
#include <asm/idprom.h>
#include <asm/machines.h>
-#include <asm/sbus.h>
-
-#if 0
-static struct resource sun4c_timer_eb = { "sun4c_timer" };
-static struct resource sun4c_intr_eb = { "sun4c_intr" };
-#endif
/*
* Bit field defines for the interrupt registers on various
@@ -64,19 +59,7 @@ static struct resource sun4c_intr_eb = { "sun4c_intr" };
*
* so don't go making it static, like I tried. sigh.
*/
-unsigned char *interrupt_enable = NULL;
-
-static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
-
-static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev,
- unsigned int sbint)
-{
- if (sbint >= sizeof(sun4c_pil_map)) {
- printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
- BUG();
- }
- return sun4c_pil_map[sbint];
-}
+unsigned char __iomem *interrupt_enable = NULL;
static void sun4c_disable_irq(unsigned int irq_nr)
{
@@ -85,7 +68,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
local_irq_save(flags);
irq_nr &= (NR_IRQS - 1);
- current_mask = *interrupt_enable;
+ current_mask = sbus_readb(interrupt_enable);
switch(irq_nr) {
case 1:
new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
@@ -103,7 +86,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
local_irq_restore(flags);
return;
}
- *interrupt_enable = new_mask;
+ sbus_writeb(new_mask, interrupt_enable);
local_irq_restore(flags);
}
@@ -114,7 +97,7 @@ static void sun4c_enable_irq(unsigned int irq_nr)
local_irq_save(flags);
irq_nr &= (NR_IRQS - 1);
- current_mask = *interrupt_enable;
+ current_mask = sbus_readb(interrupt_enable);
switch(irq_nr) {
case 1:
new_mask = ((current_mask) | SUN4C_INT_E1);
@@ -132,37 +115,22 @@ static void sun4c_enable_irq(unsigned int irq_nr)
local_irq_restore(flags);
return;
}
- *interrupt_enable = new_mask;
+ sbus_writeb(new_mask, interrupt_enable);
local_irq_restore(flags);
}
-#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */
-#define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */
-
-volatile struct sun4c_timer_info *sun4c_timers;
+struct sun4c_timer_info {
+ u32 l10_count;
+ u32 l10_limit;
+ u32 l14_count;
+ u32 l14_limit;
+};
-#ifdef CONFIG_SUN4
-/* This is an ugly hack to work around the
- current timer code, and make it work with
- the sun4/260 intersil
- */
-volatile struct sun4c_timer_info sun4_timer;
-#endif
+static struct sun4c_timer_info __iomem *sun4c_timers;
static void sun4c_clear_clock_irq(void)
{
- volatile unsigned int clear_intr;
-#ifdef CONFIG_SUN4
- if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
- clear_intr = sun4_timer.timer_limit10;
- else
-#endif
- clear_intr = sun4c_timers->timer_limit10;
-}
-
-static void sun4c_clear_profile_irq(int cpu)
-{
- /* Errm.. not sure how to do this.. */
+ sbus_readl(&sun4c_timers->l10_limit);
}
static void sun4c_load_profile_irq(int cpu, unsigned int limit)
@@ -172,41 +140,48 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
static void __init sun4c_init_timers(irq_handler_t counter_fn)
{
- int irq;
+ const struct linux_prom_irqs *irq;
+ struct device_node *dp;
+ const u32 *addr;
+ int err;
+
+ dp = of_find_node_by_name(NULL, "counter-timer");
+ if (!dp) {
+ prom_printf("sun4c_init_timers: Unable to find counter-timer\n");
+ prom_halt();
+ }
- /* Map the Timer chip, this is implemented in hardware inside
- * the cache chip on the sun4c.
- */
-#ifdef CONFIG_SUN4
- if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
- sun4c_timers = &sun4_timer;
- else
-#endif
- sun4c_timers = ioremap(SUN_TIMER_PHYSADDR,
- sizeof(struct sun4c_timer_info));
+ addr = of_get_property(dp, "address", NULL);
+ if (!addr) {
+ prom_printf("sun4c_init_timers: No address property\n");
+ prom_halt();
+ }
+
+ sun4c_timers = (void __iomem *) (unsigned long) addr[0];
+
+ irq = of_get_property(dp, "intr", NULL);
+ if (!irq) {
+ prom_printf("sun4c_init_timers: No intr property\n");
+ prom_halt();
+ }
/* Have the level 10 timer tick at 100HZ. We don't touch the
* level 14 timer limit since we are letting the prom handle
* them until we have a real console driver so L1-A works.
*/
- sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
- master_l10_counter = &sun4c_timers->cur_count10;
- master_l10_limit = &sun4c_timers->timer_limit10;
+ sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit);
- irq = request_irq(TIMER_IRQ,
- counter_fn,
+ master_l10_counter = &sun4c_timers->l10_count;
+
+ err = request_irq(irq[0].pri, counter_fn,
(IRQF_DISABLED | SA_STATIC_ALLOC),
"timer", NULL);
- if (irq) {
- prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+ if (err) {
+ prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
prom_halt();
}
-#if 0
- /* This does not work on 4/330 */
- sun4c_enable_irq(10);
-#endif
- claim_ticker14(NULL, PROFILE_IRQ, 0);
+ sun4c_disable_irq(irq[1].pri);
}
#ifdef CONFIG_SMP
@@ -215,41 +190,28 @@ static void sun4c_nop(void) {}
void __init sun4c_init_IRQ(void)
{
- struct linux_prom_registers int_regs[2];
- int ie_node;
+ struct device_node *dp;
+ const u32 *addr;
- if (ARCH_SUN4) {
- interrupt_enable = (char *)
- ioremap(sun4_ie_physaddr, PAGE_SIZE);
- } else {
- struct resource phyres;
-
- ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
- "interrupt-enable");
- if(ie_node == 0)
- panic("Cannot find /interrupt-enable node");
+ dp = of_find_node_by_name(NULL, "interrupt-enable");
+ if (!dp) {
+ prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n");
+ prom_halt();
+ }
- /* Depending on the "address" property is bad news... */
- interrupt_enable = NULL;
- if (prom_getproperty(ie_node, "reg", (char *) int_regs,
- sizeof(int_regs)) != -1) {
- memset(&phyres, 0, sizeof(struct resource));
- phyres.flags = int_regs[0].which_io;
- phyres.start = int_regs[0].phys_addr;
- interrupt_enable = (char *) sbus_ioremap(&phyres, 0,
- int_regs[0].reg_size, "sun4c_intr");
- }
+ addr = of_get_property(dp, "address", NULL);
+ if (!addr) {
+ prom_printf("sun4c_init_IRQ: No address property\n");
+ prom_halt();
}
- if (!interrupt_enable)
- panic("Cannot map interrupt_enable");
- BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
+ interrupt_enable = (void __iomem *) (unsigned long) addr[0];
+
BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
sparc_init_timers = sun4c_init_timers;
#ifdef CONFIG_SMP
@@ -257,6 +219,6 @@ void __init sun4c_init_IRQ(void)
BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
#endif
- *interrupt_enable = (SUN4C_INT_ENABLE);
+ sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable);
/* Cannot enable interrupts until OBP ticker is disabled. */
}
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 1290b5998f8..d3cb76ce418 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -19,6 +19,8 @@
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/seq_file.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -34,7 +36,6 @@
#include <asm/io.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/sbi.h>
#include <asm/cacheflush.h>
#include <asm/irq_regs.h>
@@ -44,16 +45,22 @@
/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
/* #define DISTRIBUTE_IRQS */
-struct sun4d_timer_regs *sun4d_timers;
+struct sun4d_timer_regs {
+ u32 l10_timer_limit;
+ u32 l10_cur_countx;
+ u32 l10_limit_noclear;
+ u32 ctrl;
+ u32 l10_cur_count;
+};
+
+static struct sun4d_timer_regs __iomem *sun4d_timers;
+
#define TIMER_IRQ 10
#define MAX_STATIC_ALLOC 4
extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
extern int static_irq_count;
-unsigned char cpu_leds[32];
-#ifdef CONFIG_SMP
static unsigned char sbus_tid[32];
-#endif
static struct irqaction *irq_action[NR_IRQS];
extern spinlock_t irq_action_lock;
@@ -72,9 +79,9 @@ static int sbus_to_pil[] = {
};
static int nsbi;
-#ifdef CONFIG_SMP
+
+/* Exported for sun4d_smp.c */
DEFINE_SPINLOCK(sun4d_imsk_lock);
-#endif
int show_sun4d_interrupts(struct seq_file *p, void *v)
{
@@ -257,26 +264,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
set_irq_regs(old_regs);
}
-unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
-{
- int sbusl = pil_to_sbus[irq];
-
- if (sbusl)
- return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
- else
- return irq;
-}
-
-static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev,
- unsigned int sbint)
-{
- if (sbint >= sizeof(sbus_to_pil)) {
- printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
- BUG();
- }
- return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
-}
-
int sun4d_request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long irqflags, const char * devname, void *dev_id)
@@ -360,36 +347,28 @@ out:
static void sun4d_disable_irq(unsigned int irq)
{
-#ifdef CONFIG_SMP
int tid = sbus_tid[(irq >> 5) - 1];
unsigned long flags;
-#endif
- if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+ if (irq < NR_IRQS)
+ return;
+
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else
- cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
}
static void sun4d_enable_irq(unsigned int irq)
{
-#ifdef CONFIG_SMP
int tid = sbus_tid[(irq >> 5) - 1];
unsigned long flags;
-#endif
- if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+ if (irq < NR_IRQS)
+ return;
+
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else
- cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
}
#ifdef CONFIG_SMP
@@ -409,47 +388,55 @@ static void sun4d_set_udt(int cpu)
/* Setup IRQ distribution scheme. */
void __init sun4d_distribute_irqs(void)
{
+ struct device_node *dp;
+
#ifdef DISTRIBUTE_IRQS
- struct sbus_bus *sbus;
- unsigned long sbus_serving_map;
+ cpumask_t sbus_serving_map;
sbus_serving_map = cpu_present_map;
- for_each_sbus(sbus) {
- if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
- sbus_tid[sbus->board] = (sbus->board * 2 + 1);
- else if (cpu_present_map & (1 << (sbus->board * 2)))
- sbus_tid[sbus->board] = (sbus->board * 2);
- else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
- sbus_tid[sbus->board] = (sbus->board * 2 + 1);
+ for_each_node_by_name(dp, "sbi") {
+ int board = of_getintprop_default(dp, "board#", 0);
+
+ if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map))
+ sbus_tid[board] = (board * 2 + 1);
+ else if (cpu_isset(board * 2, cpu_present_map))
+ sbus_tid[board] = (board * 2);
+ else if (cpu_isset(board * 2 + 1, cpu_present_map))
+ sbus_tid[board] = (board * 2 + 1);
else
- sbus_tid[sbus->board] = 0xff;
- if (sbus_tid[sbus->board] != 0xff)
- sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
+ sbus_tid[board] = 0xff;
+ if (sbus_tid[board] != 0xff)
+ cpu_clear(sbus_tid[board], sbus_serving_map);
}
- for_each_sbus(sbus)
- if (sbus_tid[sbus->board] == 0xff) {
+ for_each_node_by_name(dp, "sbi") {
+ int board = of_getintprop_default(dp, "board#", 0);
+ if (sbus_tid[board] == 0xff) {
int i = 31;
- if (!sbus_serving_map)
+ if (cpus_empty(sbus_serving_map))
sbus_serving_map = cpu_present_map;
- while (!(sbus_serving_map & (1 << i)))
+ while (cpu_isset(i, sbus_serving_map))
i--;
- sbus_tid[sbus->board] = i;
- sbus_serving_map &= ~(1 << i);
+ sbus_tid[board] = i;
+ cpu_clear(i, sbus_serving_map);
}
- for_each_sbus(sbus) {
- printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]);
- set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
+ }
+ for_each_node_by_name(dp, "sbi") {
+ int devid = of_getintprop_default(dp, "device-id", 0);
+ int board = of_getintprop_default(dp, "board#", 0);
+ printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]);
+ set_sbi_tid(devid, sbus_tid[board] << 3);
}
#else
- struct sbus_bus *sbus;
int cpuid = cpu_logical_map(1);
if (cpuid == -1)
cpuid = cpu_logical_map(0);
- for_each_sbus(sbus) {
- sbus_tid[sbus->board] = cpuid;
- set_sbi_tid(sbus->devid, cpuid << 3);
+ for_each_node_by_name(dp, "sbi") {
+ int devid = of_getintprop_default(dp, "device-id", 0);
+ int board = of_getintprop_default(dp, "board#", 0);
+ sbus_tid[board] = cpuid;
+ set_sbi_tid(devid, cpuid << 3);
}
printk("All sbus IRQs directed to CPU%d\n", cpuid);
#endif
@@ -458,13 +445,7 @@ void __init sun4d_distribute_irqs(void)
static void sun4d_clear_clock_irq(void)
{
- volatile unsigned int clear_intr;
- clear_intr = sun4d_timers->l10_timer_limit;
-}
-
-static void sun4d_clear_profile_irq(int cpu)
-{
- bw_get_prof_limit(cpu);
+ sbus_readl(&sun4d_timers->l10_timer_limit);
}
static void sun4d_load_profile_irq(int cpu, unsigned int limit)
@@ -472,98 +453,121 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
bw_set_prof_limit(cpu, limit);
}
-static void __init sun4d_init_timers(irq_handler_t counter_fn)
+static void __init sun4d_load_profile_irqs(void)
{
- int irq;
- int cpu;
- struct resource r;
- int mid;
+ int cpu = 0, mid;
- /* Map the User Timer registers. */
- memset(&r, 0, sizeof(r));
+ while (!cpu_find_by_instance(cpu, NULL, &mid)) {
+ sun4d_load_profile_irq(mid >> 3, 0);
+ cpu++;
+ }
+}
+
+static void __init sun4d_fixup_trap_table(void)
+{
#ifdef CONFIG_SMP
- r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
-#else
- r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
+ unsigned long flags;
+ extern unsigned long lvl14_save[4];
+ struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
+ extern unsigned int real_irq_entry[], smp4d_ticker[];
+ extern unsigned int patchme_maybe_smp_msg[];
+
+ /* Adjust so that we jump directly to smp4d_ticker */
+ lvl14_save[2] += smp4d_ticker - real_irq_entry;
+
+ /* For SMP we use the level 14 ticker, however the bootup code
+ * has copied the firmware's level 14 vector into the boot cpu's
+ * trap table, we must fix this now or we get squashed.
+ */
+ local_irq_save(flags);
+ patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+ trap_table->inst_one = lvl14_save[0];
+ trap_table->inst_two = lvl14_save[1];
+ trap_table->inst_three = lvl14_save[2];
+ trap_table->inst_four = lvl14_save[3];
+ local_flush_cache_all();
+ local_irq_restore(flags);
#endif
- r.flags = 0xf;
- sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
- PAGE_SIZE, "user timer");
+}
- sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
- master_l10_counter = &sun4d_timers->l10_cur_count;
- master_l10_limit = &sun4d_timers->l10_timer_limit;
+static void __init sun4d_init_timers(irq_handler_t counter_fn)
+{
+ struct device_node *dp;
+ struct resource res;
+ const u32 *reg;
+ int err;
+
+ dp = of_find_node_by_name(NULL, "cpu-unit");
+ if (!dp) {
+ prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
+ prom_halt();
+ }
- irq = request_irq(TIMER_IRQ,
- counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "timer", NULL);
- if (irq) {
- prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+ /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
+ * registers via any cpu's mapping. The first 'reg' property is the
+ * bootbus.
+ */
+ reg = of_get_property(dp, "reg", NULL);
+ if (!reg) {
+ prom_printf("sun4d_init_timers: No reg property\n");
prom_halt();
}
-
- /* Enable user timer free run for CPU 0 in BW */
- /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
- cpu = 0;
- while (!cpu_find_by_instance(cpu, NULL, &mid)) {
- sun4d_load_profile_irq(mid >> 3, 0);
- cpu++;
+ res.start = reg[1];
+ res.end = reg[2] - 1;
+ res.flags = reg[0] & 0xff;
+ sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
+ sizeof(struct sun4d_timer_regs), "user timer");
+ if (!sun4d_timers) {
+ prom_printf("sun4d_init_timers: Can't map timer regs\n");
+ prom_halt();
}
-
-#ifdef CONFIG_SMP
- {
- unsigned long flags;
- extern unsigned long lvl14_save[4];
- struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
- extern unsigned int real_irq_entry[], smp4d_ticker[];
- extern unsigned int patchme_maybe_smp_msg[];
-
- /* Adjust so that we jump directly to smp4d_ticker */
- lvl14_save[2] += smp4d_ticker - real_irq_entry;
-
- /* For SMP we use the level 14 ticker, however the bootup code
- * has copied the firmware's level 14 vector into the boot cpu's
- * trap table, we must fix this now or we get squashed.
- */
- local_irq_save(flags);
- patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
- trap_table->inst_one = lvl14_save[0];
- trap_table->inst_two = lvl14_save[1];
- trap_table->inst_three = lvl14_save[2];
- trap_table->inst_four = lvl14_save[3];
- local_flush_cache_all();
- local_irq_restore(flags);
+
+ sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
+
+ master_l10_counter = &sun4d_timers->l10_cur_count;
+
+ err = request_irq(TIMER_IRQ, counter_fn,
+ (IRQF_DISABLED | SA_STATIC_ALLOC),
+ "timer", NULL);
+ if (err) {
+ prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
+ prom_halt();
}
-#endif
+ sun4d_load_profile_irqs();
+ sun4d_fixup_trap_table();
}
void __init sun4d_init_sbi_irq(void)
{
- struct sbus_bus *sbus;
- unsigned mask;
+ struct device_node *dp;
+ int target_cpu = 0;
+
+#ifdef CONFIG_SMP
+ target_cpu = boot_cpu_id;
+#endif
nsbi = 0;
- for_each_sbus(sbus)
+ for_each_node_by_name(dp, "sbi")
nsbi++;
sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
if (!sbus_actions) {
prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
prom_halt();
}
- for_each_sbus(sbus) {
-#ifdef CONFIG_SMP
- extern unsigned char boot_cpu_id;
-
- set_sbi_tid(sbus->devid, boot_cpu_id << 3);
- sbus_tid[sbus->board] = boot_cpu_id;
-#endif
+ for_each_node_by_name(dp, "sbi") {
+ int devid = of_getintprop_default(dp, "device-id", 0);
+ int board = of_getintprop_default(dp, "board#", 0);
+ unsigned int mask;
+
+ set_sbi_tid(devid, target_cpu << 3);
+ sbus_tid[board] = target_cpu;
+
/* Get rid of pending irqs from PROM */
- mask = acquire_sbi(sbus->devid, 0xffffffff);
+ mask = acquire_sbi(devid, 0xffffffff);
if (mask) {
- printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
- release_sbi(sbus->devid, mask);
+ printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board);
+ release_sbi(devid, mask);
}
}
}
@@ -572,11 +576,9 @@ void __init sun4d_init_IRQ(void)
{
local_irq_disable();
- BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
sparc_init_timers = sun4d_init_timers;
#ifdef CONFIG_SMP
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 446767e8f56..7a6a5e79592 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -20,6 +20,7 @@
#include <linux/swap.h>
#include <linux/profile.h>
#include <linux/delay.h>
+#include <linux/cpu.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
@@ -30,7 +31,6 @@
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
-#include <asm/sbus.h>
#include <asm/sbi.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
@@ -72,6 +72,17 @@ static void smp_setup_percpu_timer(void);
extern void cpu_probe(void);
extern void sun4d_distribute_irqs(void);
+static unsigned char cpu_leds[32];
+
+static inline void show_leds(int cpuid)
+{
+ cpuid &= 0x1e;
+ __asm__ __volatile__ ("stba %0, [%1] %2" : :
+ "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
+ "r" (ECSR_BASE(cpuid) | BB_LEDS),
+ "i" (ASI_M_CTL));
+}
+
void __init smp4d_callin(void)
{
int cpuid = hard_smp4d_processor_id();
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 94e02de960e..f10317179ee 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -20,6 +20,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -35,59 +37,27 @@
#include <asm/smp.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/cacheflush.h>
#include "irq.h"
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
- unsigned int tbt; /* Interrupts still pending for this cpu. */
-
- /* These next two registers are WRITE-ONLY and are only
- * "on bit" sensitive, "off bits" written have NO affect.
- */
- unsigned int clear; /* Clear this cpus irqs here. */
- unsigned int set; /* Set this cpus irqs here. */
- unsigned char space[PAGE_SIZE - 12];
+struct sun4m_irq_percpu {
+ u32 pending;
+ u32 clear;
+ u32 set;
};
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- * sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
- struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
- unsigned int tbt; /* IRQ's that are still pending. */
- unsigned int irqs; /* Master IRQ bits. */
-
- /* Again, like the above, two these registers are WRITE-ONLY. */
- unsigned int clear; /* Clear master IRQ's by setting bits here. */
- unsigned int set; /* Set master IRQ's by setting bits here. */
-
- /* This register is both READ and WRITE. */
- unsigned int undirected_target; /* Which cpu gets undirected irqs. */
+struct sun4m_irq_global {
+ u32 pending;
+ u32 mask;
+ u32 mask_clear;
+ u32 mask_set;
+ u32 interrupt_target;
};
-static unsigned long dummy;
-
-struct sun4m_intregs *sun4m_interrupts;
-unsigned long *irq_rcvreg = &dummy;
+/* Code in entry.S needs to get at these register mappings. */
+struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
+struct sun4m_irq_global __iomem *sun4m_irq_global;
/* Dave Redman (djhr@tadpole.co.uk)
* The sun4m interrupt registers.
@@ -101,8 +71,9 @@ unsigned long *irq_rcvreg = &dummy;
#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
-#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
-#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
+#define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */
+#define SUN4M_INT_ECC_ERR 0x10000000 /* ecc memory error */
+#define SUN4M_INT_VME_ERR 0x08000000 /* vme async error */
#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
@@ -113,75 +84,126 @@ unsigned long *irq_rcvreg = &dummy;
#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
+#define SUN4M_INT_VMEBITS 0x0000007F /* vme int bits */
+
+#define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \
+ SUN4M_INT_M2S_WRITE_ERR | \
+ SUN4M_INT_ECC_ERR | \
+ SUN4M_INT_VME_ERR)
#define SUN4M_INT_SBUS(x) (1 << (x+7))
#define SUN4M_INT_VME(x) (1 << (x))
-/* These tables only apply for interrupts greater than 15..
- *
- * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but that's how I've done it.
- * and it won't clash with what OBP is telling us about devices.
+/* Interrupt levels used by OBP */
+#define OBP_INT_LEVEL_SOFT 0x10
+#define OBP_INT_LEVEL_ONBOARD 0x20
+#define OBP_INT_LEVEL_SBUS 0x30
+#define OBP_INT_LEVEL_VME 0x40
+
+/* Interrupt level assignment on sun4m:
+ *
+ * level source
+ * ------------------------------------------------------------
+ * 1 softint-1
+ * 2 softint-2, VME/SBUS level 1
+ * 3 softint-3, VME/SBUS level 2
+ * 4 softint-4, onboard SCSI
+ * 5 softint-5, VME/SBUS level 3
+ * 6 softint-6, onboard ETHERNET
+ * 7 softint-7, VME/SBUS level 4
+ * 8 softint-8, onboard VIDEO
+ * 9 softint-9, VME/SBUS level 5, Module Interrupt
+ * 10 softint-10, system counter/timer
+ * 11 softint-11, VME/SBUS level 6, Floppy
+ * 12 softint-12, Keyboard/Mouse, Serial
+ * 13 softint-13, VME/SBUS level 7, ISDN Audio
+ * 14 softint-14, per-processor counter/timer
+ * 15 softint-15, Asynchronous Errors (broadcast)
*
- * take an encoded intr value and lookup if it's valid
- * then get the mask bits that match from irq_mask
+ * Each interrupt source is masked distinctly in the sun4m interrupt
+ * registers. The PIL level alone is therefore ambiguous, since multiple
+ * interrupt sources map to a single PIL.
*
- * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
+ * This ambiguity is resolved in the 'intr' property for device nodes
+ * in the OF device tree. Each 'intr' property entry is composed of
+ * two 32-bit words. The first word is the IRQ priority value, which
+ * is what we're intersted in. The second word is the IRQ vector, which
+ * is unused.
+ *
+ * The low 4 bits of the IRQ priority indicate the PIL, and the upper
+ * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled. 0x20
+ * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
+ *
+ * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
+ * whereas a value of 0x33 is SBUS level 2. Here are some sample
+ * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
+ * Tadpole S3 GX systems.
+ *
+ * esp: 0x24 onboard ESP SCSI
+ * le: 0x26 onboard Lance ETHERNET
+ * p9100: 0x32 SBUS level 1 P9100 video
+ * bpp: 0x33 SBUS level 2 BPP parallel port device
+ * DBRI: 0x39 SBUS level 5 DBRI ISDN audio
+ * SUNW,leo: 0x39 SBUS level 5 LEO video
+ * pcmcia: 0x3b SBUS level 6 PCMCIA controller
+ * uctrl: 0x3b SBUS level 6 UCTRL device
+ * modem: 0x3d SBUS level 7 MODEM
+ * zs: 0x2c onboard keyboard/mouse/serial
+ * floppy: 0x2b onboard Floppy
+ * power: 0x22 onboard power device (XXX unknown mask bit XXX)
*/
-static unsigned char irq_xlate[32] = {
- /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */
- 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7,
- 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0
-};
-static unsigned long irq_mask[] = {
- 0, /* illegal index */
- SUN4M_INT_SCSI, /* 1 irq 4 */
- SUN4M_INT_ETHERNET, /* 2 irq 6 */
- SUN4M_INT_VIDEO, /* 3 irq 8 */
- SUN4M_INT_REALTIME, /* 4 irq 10 */
- SUN4M_INT_FLOPPY, /* 5 irq 11 */
- (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */
- SUN4M_INT_MODULE_ERR, /* 7 irq 15 */
- SUN4M_INT_SBUS(0), /* 8 irq 2 */
- SUN4M_INT_SBUS(1), /* 9 irq 3 */
- SUN4M_INT_SBUS(2), /* 10 irq 5 */
- SUN4M_INT_SBUS(3), /* 11 irq 7 */
- SUN4M_INT_SBUS(4), /* 12 irq 9 */
- SUN4M_INT_SBUS(5), /* 13 irq 11 */
- SUN4M_INT_SBUS(6) /* 14 irq 13 */
+static unsigned long irq_mask[0x50] = {
+ /* SMP */
+ 0, SUN4M_SOFT_INT(1),
+ SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
+ SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
+ SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
+ SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
+ SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+ SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+ SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+ /* soft */
+ 0, SUN4M_SOFT_INT(1),
+ SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
+ SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5),
+ SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7),
+ SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9),
+ SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+ SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+ SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+ /* onboard */
+ 0, 0, 0, 0,
+ SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0,
+ SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
+ SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
+ (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
+ SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+ /* sbus */
+ 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
+ 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
+ 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
+ 0, SUN4M_INT_SBUS(6), 0, 0,
+ /* vme */
+ 0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
+ 0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
+ 0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
+ 0, SUN4M_INT_VME(6), 0, 0
};
-static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
-
-static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev,
- unsigned int sbint)
-{
- if (sbint >= sizeof(sun4m_pil_map)) {
- printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
- BUG();
- }
- return sun4m_pil_map[sbint] | 0x30;
-}
-
static unsigned long sun4m_get_irqmask(unsigned int irq)
{
unsigned long mask;
- if (irq > 0x20) {
- /* OBIO/SBUS interrupts */
- irq &= 0x1f;
- mask = irq_mask[irq_xlate[irq]];
- if (!mask)
- printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
- } else {
- /* Soft Interrupts will come here.
- * Currently there is no way to trigger them but I'm sure
- * something could be cooked up.
- */
- irq &= 0xf;
- mask = SUN4M_SOFT_INT(irq);
- }
+ if (irq < 0x50)
+ mask = irq_mask[irq];
+ else
+ mask = 0;
+
+ if (!mask)
+ printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
+ irq);
+
return mask;
}
@@ -193,9 +215,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags);
if (irq_nr > 15)
- sun4m_interrupts->set = mask;
+ sbus_writel(mask, &sun4m_irq_global->mask_set);
else
- sun4m_interrupts->cpu_intregs[cpu].set = mask;
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
local_irq_restore(flags);
}
@@ -212,13 +234,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags);
if (irq_nr > 15)
- sun4m_interrupts->clear = mask;
+ sbus_writel(mask, &sun4m_irq_global->mask_clear);
else
- sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
local_irq_restore(flags);
} else {
local_irq_save(flags);
- sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
+ sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
local_irq_restore(flags);
}
}
@@ -236,10 +258,10 @@ static unsigned long cpu_pil_to_imask[16] = {
/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
/*10*/ SUN4M_INT_REALTIME,
/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/ SUN4M_INT_AUDIO,
+/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
+/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
/*14*/ SUN4M_INT_E14,
-/*15*/ 0x00000000
+/*15*/ SUN4M_INT_ERROR
};
/* We assume the caller has disabled local interrupts when these are called,
@@ -247,126 +269,141 @@ static unsigned long cpu_pil_to_imask[16] = {
*/
static void sun4m_disable_pil_irq(unsigned int pil)
{
- sun4m_interrupts->set = cpu_pil_to_imask[pil];
+ sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
}
static void sun4m_enable_pil_irq(unsigned int pil)
{
- sun4m_interrupts->clear = cpu_pil_to_imask[pil];
+ sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
}
#ifdef CONFIG_SMP
static void sun4m_send_ipi(int cpu, int level)
{
- unsigned long mask;
-
- mask = sun4m_get_irqmask(level);
- sun4m_interrupts->cpu_intregs[cpu].set = mask;
+ unsigned long mask = sun4m_get_irqmask(level);
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
}
static void sun4m_clear_ipi(int cpu, int level)
{
- unsigned long mask;
-
- mask = sun4m_get_irqmask(level);
- sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+ unsigned long mask = sun4m_get_irqmask(level);
+ sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
}
static void sun4m_set_udt(int cpu)
{
- sun4m_interrupts->undirected_target = cpu;
+ sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
}
#endif
-#define OBIO_INTR 0x20
-#define TIMER_IRQ (OBIO_INTR | 10)
-#define PROFILE_IRQ (OBIO_INTR | 14)
+struct sun4m_timer_percpu {
+ u32 l14_limit;
+ u32 l14_count;
+ u32 l14_limit_noclear;
+ u32 user_timer_start_stop;
+};
+
+static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
+
+struct sun4m_timer_global {
+ u32 l10_limit;
+ u32 l10_count;
+ u32 l10_limit_noclear;
+ u32 reserved;
+ u32 timer_config;
+};
+
+static struct sun4m_timer_global __iomem *timers_global;
+
+#define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10)
-static struct sun4m_timer_regs *sun4m_timers;
unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
static void sun4m_clear_clock_irq(void)
{
- volatile unsigned int clear_intr;
- clear_intr = sun4m_timers->l10_timer_limit;
+ sbus_readl(&timers_global->l10_limit);
}
-static void sun4m_clear_profile_irq(int cpu)
+void sun4m_nmi(struct pt_regs *regs)
{
- volatile unsigned int clear;
-
- clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
+ unsigned long afsr, afar, si;
+
+ printk(KERN_ERR "Aieee: sun4m NMI received!\n");
+ /* XXX HyperSparc hack XXX */
+ __asm__ __volatile__("mov 0x500, %%g1\n\t"
+ "lda [%%g1] 0x4, %0\n\t"
+ "mov 0x600, %%g1\n\t"
+ "lda [%%g1] 0x4, %1\n\t" :
+ "=r" (afsr), "=r" (afar));
+ printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
+ si = sbus_readl(&sun4m_irq_global->pending);
+ printk(KERN_ERR "si=%08lx\n", si);
+ if (si & SUN4M_INT_MODULE_ERR)
+ printk(KERN_ERR "Module async error\n");
+ if (si & SUN4M_INT_M2S_WRITE_ERR)
+ printk(KERN_ERR "MBus/SBus async error\n");
+ if (si & SUN4M_INT_ECC_ERR)
+ printk(KERN_ERR "ECC memory error\n");
+ if (si & SUN4M_INT_VME_ERR)
+ printk(KERN_ERR "VME async error\n");
+ printk(KERN_ERR "you lose buddy boy...\n");
+ show_regs(regs);
+ prom_halt();
+}
+
+/* Exported for sun4m_smp.c */
+void sun4m_clear_profile_irq(int cpu)
+{
+ sbus_readl(&timers_percpu[cpu]->l14_limit);
}
static void sun4m_load_profile_irq(int cpu, unsigned int limit)
{
- sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
+ sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
}
static void __init sun4m_init_timers(irq_handler_t counter_fn)
{
- int reg_count, irq, cpu;
- struct linux_prom_registers cnt_regs[PROMREG_MAX];
- int obio_node, cnt_node;
- struct resource r;
-
- cnt_node = 0;
- if((obio_node =
- prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
- (obio_node = prom_getchild (obio_node)) == 0 ||
- (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
- prom_printf("Cannot find /obio/counter node\n");
- prom_halt();
+ struct device_node *dp = of_find_node_by_name(NULL, "counter");
+ int i, err, len, num_cpu_timers;
+ const u32 *addr;
+
+ if (!dp) {
+ printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
+ return;
}
- reg_count = prom_getproperty(cnt_node, "reg",
- (void *) cnt_regs, sizeof(cnt_regs));
- reg_count = (reg_count/sizeof(struct linux_prom_registers));
-
- /* Apply the obio ranges to the timer registers. */
- prom_apply_obio_ranges(cnt_regs, reg_count);
-
- cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
- cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
- cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
- for(obio_node = 1; obio_node < 4; obio_node++) {
- cnt_regs[obio_node].phys_addr =
- cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
- cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
- cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
+
+ addr = of_get_property(dp, "address", &len);
+ if (!addr) {
+ printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
+ return;
}
- memset((char*)&r, 0, sizeof(struct resource));
- /* Map the per-cpu Counter registers. */
- r.flags = cnt_regs[0].which_io;
- r.start = cnt_regs[0].phys_addr;
- sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
- PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
- /* Map the system Counter register. */
- /* XXX Here we expect consequent calls to yeld adjusent maps. */
- r.flags = cnt_regs[4].which_io;
- r.start = cnt_regs[4].phys_addr;
- sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
-
- sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
- master_l10_counter = &sun4m_timers->l10_cur_count;
- master_l10_limit = &sun4m_timers->l10_timer_limit;
-
- irq = request_irq(TIMER_IRQ,
- counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "timer", NULL);
- if (irq) {
- prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
- prom_halt();
+ num_cpu_timers = (len / sizeof(u32)) - 1;
+ for (i = 0; i < num_cpu_timers; i++) {
+ timers_percpu[i] = (void __iomem *)
+ (unsigned long) addr[i];
}
-
- if (!cpu_find_by_instance(1, NULL, NULL)) {
- for(cpu = 0; cpu < 4; cpu++)
- sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
- sun4m_interrupts->set = SUN4M_INT_E14;
- } else {
- sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
+ timers_global = (void __iomem *)
+ (unsigned long) addr[num_cpu_timers];
+
+ sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
+
+ master_l10_counter = &timers_global->l10_count;
+
+ err = request_irq(TIMER_IRQ, counter_fn,
+ (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+ if (err) {
+ printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
+ err);
+ return;
}
+
+ for (i = 0; i < num_cpu_timers; i++)
+ sbus_writel(0, &timers_percpu[i]->l14_limit);
+ if (num_cpu_timers == 4)
+ sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
+
#ifdef CONFIG_SMP
{
unsigned long flags;
@@ -390,70 +427,43 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
void __init sun4m_init_IRQ(void)
{
- int ie_node,i;
- struct linux_prom_registers int_regs[PROMREG_MAX];
- int num_regs;
- struct resource r;
- int mid;
-
- local_irq_disable();
- if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
- (ie_node = prom_getchild (ie_node)) == 0 ||
- (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
- prom_printf("Cannot find /obio/interrupt node\n");
- prom_halt();
+ struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
+ int len, i, mid, num_cpu_iregs;
+ const u32 *addr;
+
+ if (!dp) {
+ printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
+ return;
}
- num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
- sizeof(int_regs));
- num_regs = (num_regs/sizeof(struct linux_prom_registers));
-
- /* Apply the obio ranges to these registers. */
- prom_apply_obio_ranges(int_regs, num_regs);
-
- int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
- int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
- int_regs[4].which_io = int_regs[num_regs-1].which_io;
- for(ie_node = 1; ie_node < 4; ie_node++) {
- int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
- int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
- int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
+
+ addr = of_get_property(dp, "address", &len);
+ if (!addr) {
+ printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
+ return;
}
- memset((char *)&r, 0, sizeof(struct resource));
- /* Map the interrupt registers for all possible cpus. */
- r.flags = int_regs[0].which_io;
- r.start = int_regs[0].phys_addr;
- sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
- PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
+ num_cpu_iregs = (len / sizeof(u32)) - 1;
+ for (i = 0; i < num_cpu_iregs; i++) {
+ sun4m_irq_percpu[i] = (void __iomem *)
+ (unsigned long) addr[i];
+ }
+ sun4m_irq_global = (void __iomem *)
+ (unsigned long) addr[num_cpu_iregs];
- /* Map the system interrupt control registers. */
- r.flags = int_regs[4].which_io;
- r.start = int_regs[4].phys_addr;
- sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
+ local_irq_disable();
- sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
+ sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
- sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
-
- if (!cpu_find_by_instance(1, NULL, NULL)) {
- /* system wide interrupts go to cpu 0, this should always
- * be safe because it is guaranteed to be fitted or OBP doesn't
- * come up
- *
- * Not sure, but writing here on SLAVIO systems may puke
- * so I don't do it unless there is more than 1 cpu.
- */
- irq_rcvreg = (unsigned long *)
- &sun4m_interrupts->undirected_target;
- sun4m_interrupts->undirected_target = 0;
- }
- BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
+ sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
+
+ if (num_cpu_iregs == 4)
+ sbus_writel(0, &sun4m_irq_global->interrupt_target);
+
BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
sparc_init_timers = sun4m_init_timers;
#ifdef CONFIG_SMP
@@ -461,5 +471,6 @@ void __init sun4m_init_IRQ(void)
BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
#endif
+
/* Cannot enable interrupts until OBP ticker is disabled. */
}
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 9964890dc1d..5fc386d08c4 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -17,6 +17,7 @@
#include <linux/swap.h>
#include <linux/profile.h>
#include <linux/delay.h>
+#include <linux/cpu.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
@@ -315,6 +316,8 @@ void smp4m_cross_call_irq(void)
ccall_info.processors_out[i] = 1;
}
+extern void sun4m_clear_profile_irq(int cpu);
+
void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
{
struct pt_regs *old_regs;
@@ -322,7 +325,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
old_regs = set_irq_regs(regs);
- clear_profile_irq(cpu);
+ sun4m_clear_profile_irq(cpu);
profile_tick(CPU_PROFILING);
diff --git a/arch/sparc/kernel/sun4setup.c b/arch/sparc/kernel/sun4setup.c
deleted file mode 100644
index 229a52f55f1..00000000000
--- a/arch/sparc/kernel/sun4setup.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* sun4setup.c: Setup the hardware address of various items in the sun4
- * architecture. Called from idprom_init
- *
- * Copyright (C) 1998 Chris G. Davis (cdavis@cois.on.ca)
- */
-
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-int sun4_memreg_physaddr;
-int sun4_ie_physaddr;
-int sun4_clock_physaddr;
-int sun4_timer_physaddr;
-int sun4_eth_physaddr;
-int sun4_si_physaddr;
-int sun4_bwtwo_physaddr;
-int sun4_zs0_physaddr;
-int sun4_zs1_physaddr;
-int sun4_dma_physaddr;
-int sun4_esp_physaddr;
-int sun4_ie_physaddr;
-
-void __init sun4setup(void)
-{
- printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). ");
- /*
- setup standard sun4 info
- */
- sun4_ie_physaddr=SUN4_IE_PHYSADDR;
-
- /*
- setup model specific info
- */
- switch(idprom->id_machtype) {
- case (SM_SUN4 | SM_4_260 ):
- printk("Setup for a SUN4/260\n");
- sun4_memreg_physaddr=SUN4_200_MEMREG_PHYSADDR;
- sun4_clock_physaddr=SUN4_200_CLOCK_PHYSADDR;
- sun4_timer_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_eth_physaddr=SUN4_200_ETH_PHYSADDR;
- sun4_si_physaddr=SUN4_200_SI_PHYSADDR;
- sun4_bwtwo_physaddr=SUN4_200_BWTWO_PHYSADDR;
- sun4_dma_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_esp_physaddr=SUN4_UNUSED_PHYSADDR;
- break;
- case (SM_SUN4 | SM_4_330 ):
- printk("Setup for a SUN4/330\n");
- sun4_memreg_physaddr=SUN4_300_MEMREG_PHYSADDR;
- sun4_clock_physaddr=SUN4_300_CLOCK_PHYSADDR;
- sun4_timer_physaddr=SUN4_300_TIMER_PHYSADDR;
- sun4_eth_physaddr=SUN4_300_ETH_PHYSADDR;
- sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_bwtwo_physaddr=SUN4_300_BWTWO_PHYSADDR;
- sun4_dma_physaddr=SUN4_300_DMA_PHYSADDR;
- sun4_esp_physaddr=SUN4_300_ESP_PHYSADDR;
- break;
- case (SM_SUN4 | SM_4_470 ):
- printk("Setup for a SUN4/470\n");
- sun4_memreg_physaddr=SUN4_400_MEMREG_PHYSADDR;
- sun4_clock_physaddr=SUN4_400_CLOCK_PHYSADDR;
- sun4_timer_physaddr=SUN4_400_TIMER_PHYSADDR;
- sun4_eth_physaddr=SUN4_400_ETH_PHYSADDR;
- sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
- sun4_bwtwo_physaddr=SUN4_400_BWTWO_PHYSADDR;
- sun4_dma_physaddr=SUN4_400_DMA_PHYSADDR;
- sun4_esp_physaddr=SUN4_400_ESP_PHYSADDR;
- break;
- default:
- ;
- }
-}
-
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index 4d73421559c..03035c852a4 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -53,7 +53,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
/* See asm-sparc/uaccess.h */
if (len > TASK_SIZE - PAGE_SIZE)
return -ENOMEM;
- if (ARCH_SUN4C_SUN4 && len > 0x20000000)
+ if (ARCH_SUN4C && len > 0x20000000)
return -ENOMEM;
if (!addr)
addr = TASK_UNMAPPED_BASE;
@@ -65,7 +65,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
/* At this point: (!vmm || addr < vmm->vm_end). */
- if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) {
+ if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
addr = PAGE_OFFSET;
vmm = find_vma(current->mm, PAGE_OFFSET);
}
@@ -81,7 +81,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
asmlinkage unsigned long sparc_brk(unsigned long brk)
{
- if(ARCH_SUN4C_SUN4) {
+ if(ARCH_SUN4C) {
if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
return current->mm->brk;
}
@@ -221,7 +221,7 @@ out:
int sparc_mmap_check(unsigned long addr, unsigned long len)
{
- if (ARCH_SUN4C_SUN4 &&
+ if (ARCH_SUN4C &&
(len > 0x20000000 ||
(addr < 0xe0000000 && addr + len > 0x20000000)))
return -EINVAL;
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index 707bfda8657..138bbf5f872 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -1,31 +1,12 @@
/* tick14.c
- * linux/arch/sparc/kernel/tick14.c
*
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
*
* This file handles the Sparc specific level14 ticker
* This is really useful for profiling OBP uses it for keyboard
* aborts and other stuff.
- *
- *
*/
-#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/timex.h>
-#include <linux/interrupt.h>
-
-#include <asm/oplib.h>
-#include <asm/timer.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include "irq.h"
extern unsigned long lvl14_save[5];
static unsigned long *linux_lvl14 = NULL;
@@ -56,31 +37,3 @@ void install_obp_ticker(void)
linux_lvl14[2] = obp_lvl14[2];
linux_lvl14[3] = obp_lvl14[3];
}
-
-void claim_ticker14(irq_handler_t handler,
- int irq_nr, unsigned int timeout )
-{
- int cpu = smp_processor_id();
-
- /* first we copy the obp handler instructions
- */
- __disable_irq(irq_nr);
- if (!handler)
- return;
-
- linux_lvl14 = (unsigned long *)lvl14_save[4];
- obp_lvl14[0] = linux_lvl14[0];
- obp_lvl14[1] = linux_lvl14[1];
- obp_lvl14[2] = linux_lvl14[2];
- obp_lvl14[3] = linux_lvl14[3];
-
- if (!request_irq(irq_nr,
- handler,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "counter14",
- NULL)) {
- install_linux_ticker();
- load_profile_irq(cpu, timeout);
- __enable_irq(irq_nr);
- }
-}
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 0762f5db192..62c1d94cb43 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -23,22 +23,24 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
#include <linux/timex.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/profile.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <asm/oplib.h>
#include <asm/timer.h>
-#include <asm/mostek.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/idprom.h>
#include <asm/machines.h>
-#include <asm/sun4paddr.h>
#include <asm/page.h>
#include <asm/pcic.h>
#include <asm/irq_regs.h>
@@ -46,34 +48,9 @@
#include "irq.h"
DEFINE_SPINLOCK(rtc_lock);
-static enum sparc_clock_type sp_clock_typ;
-DEFINE_SPINLOCK(mostek_lock);
-void __iomem *mstk48t02_regs = NULL;
-static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
static int set_rtc_mmss(unsigned long);
static int sbus_do_settimeofday(struct timespec *tv);
-#ifdef CONFIG_SUN4
-struct intersil *intersil_clock;
-#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
- (intsil_cmd)
-
-#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
- (intsil_cmd)
-
-#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
- ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
- INTERSIL_INTR_ENABLE))
-
-#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
- ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
- INTERSIL_INTR_ENABLE))
-
-#define intersil_read_intr(intersil_reg, towhere) towhere = \
- intersil_reg->int_intr_reg
-
-#endif
-
unsigned long profile_pc(struct pt_regs *regs)
{
extern char __copy_user_begin[], __copy_user_end[];
@@ -96,7 +73,6 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc);
__volatile__ unsigned int *master_l10_counter;
-__volatile__ unsigned int *master_l10_limit;
/*
* timer_interrupt() needs to keep up the real-time clock,
@@ -116,15 +92,7 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
/* Protect counter clear so that do_gettimeoffset works */
write_seqlock(&xtime_lock);
-#ifdef CONFIG_SUN4
- if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
- (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
- int temp;
- intersil_read_intr(intersil_clock, temp);
- /* re-enable the irq */
- enable_pil_irq(10);
- }
-#endif
+
clear_clock_irq();
do_timer(1);
@@ -147,157 +115,56 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
return IRQ_HANDLED;
}
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __devinit kick_start_clock(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
{
- struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
- unsigned char sec;
- int i, count;
-
- prom_printf("CLOCK: Clock was stopped. Kick start ");
-
- spin_lock_irq(&mostek_lock);
-
- /* Turn on the kick start bit to start the oscillator. */
- regs->creg |= MSTK_CREG_WRITE;
- regs->sec &= ~MSTK_STOP;
- regs->hour |= MSTK_KICK_START;
- regs->creg &= ~MSTK_CREG_WRITE;
-
- spin_unlock_irq(&mostek_lock);
-
- /* Delay to allow the clock oscillator to start. */
- sec = MSTK_REG_SEC(regs);
- for (i = 0; i < 3; i++) {
- while (sec == MSTK_REG_SEC(regs))
- for (count = 0; count < 100000; count++)
- /* nothing */ ;
- prom_printf(".");
- sec = regs->sec;
- }
- prom_printf("\n");
-
- spin_lock_irq(&mostek_lock);
-
- /* Turn off kick start and set a "valid" time and date. */
- regs->creg |= MSTK_CREG_WRITE;
- regs->hour &= ~MSTK_KICK_START;
- MSTK_SET_REG_SEC(regs,0);
- MSTK_SET_REG_MIN(regs,0);
- MSTK_SET_REG_HOUR(regs,0);
- MSTK_SET_REG_DOW(regs,5);
- MSTK_SET_REG_DOM(regs,1);
- MSTK_SET_REG_MONTH(regs,8);
- MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
- regs->creg &= ~MSTK_CREG_WRITE;
-
- spin_unlock_irq(&mostek_lock);
-
- /* Ensure the kick start bit is off. If it isn't, turn it off. */
- while (regs->hour & MSTK_KICK_START) {
- prom_printf("CLOCK: Kick start still on!\n");
-
- spin_lock_irq(&mostek_lock);
- regs->creg |= MSTK_CREG_WRITE;
- regs->hour &= ~MSTK_KICK_START;
- regs->creg &= ~MSTK_CREG_WRITE;
- spin_unlock_irq(&mostek_lock);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ void __iomem *regs = pdata->ioaddr;
+ unsigned char val = readb(regs + ofs);
+
+ /* the year 0 is 1968 */
+ if (ofs == pdata->offset + M48T59_YEAR) {
+ val += 0x68;
+ if ((val & 0xf) > 9)
+ val += 6;
}
-
- prom_printf("CLOCK: Kick start procedure successful.\n");
-}
-
-/* Return nonzero if the clock chip battery is low. */
-static inline int has_low_battery(void)
-{
- struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
- unsigned char data1, data2;
-
- spin_lock_irq(&mostek_lock);
- data1 = regs->eeprom[0]; /* Read some data. */
- regs->eeprom[0] = ~data1; /* Write back the complement. */
- data2 = regs->eeprom[0]; /* Read back the complement. */
- regs->eeprom[0] = data1; /* Restore the original value. */
- spin_unlock_irq(&mostek_lock);
-
- return (data1 == data2); /* Was the write blocked? */
+ return val;
}
-static void __devinit mostek_set_system_time(void)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
{
- unsigned int year, mon, day, hour, min, sec;
- struct mostek48t02 *mregs;
-
- mregs = (struct mostek48t02 *)mstk48t02_regs;
- if(!mregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
- spin_lock_irq(&mostek_lock);
- mregs->creg |= MSTK_CREG_READ;
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- mregs->creg &= ~MSTK_CREG_READ;
- spin_unlock_irq(&mostek_lock);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ void __iomem *regs = pdata->ioaddr;
+
+ if (ofs == pdata->offset + M48T59_YEAR) {
+ if (val < 0x68)
+ val += 0x32;
+ else
+ val -= 0x68;
+ if ((val & 0xf) > 9)
+ val += 6;
+ if ((val & 0xf0) > 0x9A)
+ val += 0x60;
+ }
+ writeb(val, regs + ofs);
}
-/* Probe for the real time clock chip on Sun4 */
-static inline void sun4_clock_probe(void)
-{
-#ifdef CONFIG_SUN4
- int temp;
- struct resource r;
-
- memset(&r, 0, sizeof(r));
- if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
- sp_clock_typ = MSTK48T02;
- r.start = sun4_clock_physaddr;
- mstk48t02_regs = sbus_ioremap(&r, 0,
- sizeof(struct mostek48t02), NULL);
- mstk48t08_regs = NULL; /* To catch weirdness */
- intersil_clock = NULL; /* just in case */
-
- /* Kick start the clock if it is completely stopped. */
- if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
- kick_start_clock();
- } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
- /* intersil setup code */
- printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
- sp_clock_typ = INTERSIL;
- r.start = sun4_clock_physaddr;
- intersil_clock = (struct intersil *)
- sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
- mstk48t02_regs = 0; /* just be sure */
- mstk48t08_regs = NULL; /* ditto */
- /* initialise the clock */
-
- intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-
- intersil_start(intersil_clock);
-
- intersil_read_intr(intersil_clock, temp);
- while (!(temp & 0x80))
- intersil_read_intr(intersil_clock, temp);
-
- intersil_read_intr(intersil_clock, temp);
- while (!(temp & 0x80))
- intersil_read_intr(intersil_clock, temp);
-
- intersil_stop(intersil_clock);
+static struct m48t59_plat_data m48t59_data = {
+ .read_byte = mostek_read_byte,
+ .write_byte = mostek_write_byte,
+};
- }
-#endif
-}
+/* resource is set at runtime */
+static struct platform_device m48t59_rtc = {
+ .name = "rtc-m48t59",
+ .id = 0,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = &m48t59_data,
+ },
+};
-#ifndef CONFIG_SUN4
static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
@@ -306,38 +173,26 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
if (!model)
return -ENODEV;
+ m48t59_rtc.resource = &op->resource[0];
if (!strcmp(model, "mk48t02")) {
- sp_clock_typ = MSTK48T02;
-
/* Map the clock register io area read-only */
- mstk48t02_regs = of_ioremap(&op->resource[0], 0,
- sizeof(struct mostek48t02),
- "mk48t02");
- mstk48t08_regs = NULL; /* To catch weirdness */
+ m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+ 2048, "rtc-m48t59");
+ m48t59_data.type = M48T59RTC_TYPE_M48T02;
} else if (!strcmp(model, "mk48t08")) {
- sp_clock_typ = MSTK48T08;
- mstk48t08_regs = of_ioremap(&op->resource[0], 0,
- sizeof(struct mostek48t08),
- "mk48t08");
-
- mstk48t02_regs = &mstk48t08_regs->regs;
+ m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+ 8192, "rtc-m48t59");
+ m48t59_data.type = M48T59RTC_TYPE_M48T08;
} else
return -ENODEV;
- /* Report a low battery voltage condition. */
- if (has_low_battery())
- printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
-
- /* Kick start the clock if it is completely stopped. */
- if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
- kick_start_clock();
-
- mostek_set_system_time();
+ if (platform_device_register(&m48t59_rtc) < 0)
+ printk(KERN_ERR "Registering RTC device failed\n");
return 0;
}
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata clock_match[] = {
{
.name = "eeprom",
},
@@ -348,7 +203,7 @@ static struct of_platform_driver clock_driver = {
.match_table = clock_match,
.probe = clock_probe,
.driver = {
- .name = "clock",
+ .name = "rtc",
},
};
@@ -364,7 +219,6 @@ static int __init clock_init(void)
* need to see the clock registers.
*/
fs_initcall(clock_init);
-#endif /* !CONFIG_SUN4 */
static void __init sbus_time_init(void)
{
@@ -372,51 +226,8 @@ static void __init sbus_time_init(void)
BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
btfixup();
- if (ARCH_SUN4)
- sun4_clock_probe();
-
sparc_init_timers(timer_interrupt);
-#ifdef CONFIG_SUN4
- if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
- mostek_set_system_time();
- } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
- /* initialise the intersil on sun4 */
- unsigned int year, mon, day, hour, min, sec;
- int temp;
- struct intersil *iregs;
-
- iregs=intersil_clock;
- if(!iregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
-
- intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
- disable_pil_irq(10);
- intersil_stop(iregs);
- intersil_read_intr(intersil_clock, temp);
-
- temp = iregs->clk.int_csec;
-
- sec = iregs->clk.int_sec;
- min = iregs->clk.int_min;
- hour = iregs->clk.int_hour;
- day = iregs->clk.int_day;
- mon = iregs->clk.int_month;
- year = MSTK_CVT_YEAR(iregs->clk.int_year);
-
- enable_pil_irq(10);
- intersil_start(iregs);
-
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
- }
-#endif
-
/* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
local_irq_enable();
}
@@ -522,80 +333,15 @@ static int sbus_do_settimeofday(struct timespec *tv)
return 0;
}
-/*
- * BUG: This routine does not handle hour overflow properly; it just
- * sets the minutes. Usually you won't notice until after reboot!
- */
-static int set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long secs)
{
- int real_seconds, real_minutes, mostek_minutes;
- struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
- unsigned long flags;
-#ifdef CONFIG_SUN4
- struct intersil *iregs = intersil_clock;
- int temp;
-#endif
+ struct rtc_device *rtc = rtc_class_open("rtc0");
+ int err = -1;
- /* Not having a register set can lead to trouble. */
- if (!regs) {
-#ifdef CONFIG_SUN4
- if(!iregs)
- return -1;
- else {
- temp = iregs->clk.int_csec;
-
- mostek_minutes = iregs->clk.int_min;
-
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - mostek_minutes) < 30) {
- intersil_stop(iregs);
- iregs->clk.int_sec=real_seconds;
- iregs->clk.int_min=real_minutes;
- intersil_start(iregs);
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- mostek_minutes, real_minutes);
- return -1;
- }
-
- return 0;
- }
-#endif
+ if (rtc) {
+ err = rtc_set_mmss(rtc, secs);
+ rtc_class_close(rtc);
}
- spin_lock_irqsave(&mostek_lock, flags);
- /* Read the current RTC minutes. */
- regs->creg |= MSTK_CREG_READ;
- mostek_minutes = MSTK_REG_MIN(regs);
- regs->creg &= ~MSTK_CREG_READ;
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - mostek_minutes) < 30) {
- regs->creg |= MSTK_CREG_WRITE;
- MSTK_SET_REG_SEC(regs,real_seconds);
- MSTK_SET_REG_MIN(regs,real_minutes);
- regs->creg &= ~MSTK_CREG_WRITE;
- spin_unlock_irqrestore(&mostek_lock, flags);
- return 0;
- } else {
- spin_unlock_irqrestore(&mostek_lock, flags);
- return -1;
- }
+ return err;
}
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 5d45d5fd8c9..2b7d5065903 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -43,23 +43,6 @@ void syscall_trace_exit(struct pt_regs *regs)
{
}
-void sun4m_nmi(struct pt_regs *regs)
-{
- unsigned long afsr, afar;
-
- printk("Aieee: sun4m NMI received!\n");
- /* XXX HyperSparc hack XXX */
- __asm__ __volatile__("mov 0x500, %%g1\n\t"
- "lda [%%g1] 0x4, %0\n\t"
- "mov 0x600, %%g1\n\t"
- "lda [%%g1] 0x4, %1\n\t" :
- "=r" (afsr), "=r" (afar));
- printk("afsr=%08lx afar=%08lx\n", afsr, afar);
- printk("you lose buddy boy...\n");
- show_regs(regs);
- prom_halt();
-}
-
void sun4d_nmi(struct pt_regs *regs)
{
printk("Aieee: sun4d NMI received!\n");
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 109c8b22cb3..ea88955d97f 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -3,13 +3,8 @@
EXTRA_AFLAGS := -ansi
-obj-y := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
-
-ifeq ($(CONFIG_SUN4),y)
-obj-y += nosrmmu.o
-else
-obj-y += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
-endif
+obj-y := fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
+ srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
ifdef CONFIG_HIGHMEM
obj-y += highmem.o
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
index a312d127d47..5175ac2f482 100644
--- a/arch/sparc/mm/btfixup.c
+++ b/arch/sparc/mm/btfixup.c
@@ -20,11 +20,7 @@
extern char *srmmu_name;
static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
-#ifdef CONFIG_SUN4
-static char str_sun4c[] __initdata = "sun4\n";
-#else
static char str_sun4c[] __initdata = "sun4c\n";
-#endif
static char str_srmmu[] __initdata = "srmmu[%s]/";
static char str_iommu[] __initdata = "iommu\n";
static char str_iounit[] __initdata = "io-unit\n";
@@ -86,7 +82,7 @@ void __init btfixup(void)
if (!visited) {
visited++;
printk(version);
- if (ARCH_SUN4C_SUN4)
+ if (ARCH_SUN4C)
printk(str_sun4c);
else {
printk(str_srmmu, srmmu_name);
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 3604c2e8670..a507e117466 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -191,7 +191,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
* only copy the information from the master page table,
* nothing more.
*/
- if (!ARCH_SUN4C_SUN4 && address >= TASK_SIZE)
+ if (!ARCH_SUN4C && address >= TASK_SIZE)
goto vmalloc_fault;
info.si_code = SEGV_MAPERR;
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index e103f1bb377..677c1e187a2 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -23,6 +23,7 @@
#include <linux/highmem.h>
#include <linux/bootmem.h>
#include <linux/pagemap.h>
+#include <linux/poison.h>
#include <asm/system.h>
#include <asm/vac-ops.h>
@@ -480,6 +481,7 @@ void free_initmem (void)
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
struct page *p;
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
p = virt_to_page(addr);
ClearPageReserved(p);
@@ -488,20 +490,26 @@ void free_initmem (void)
totalram_pages++;
num_physpages++;
}
- printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+ printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
+ (&__init_end - &__init_begin) >> 10);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (start < end)
- printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+ (end - start) >> 10);
for (; start < end; start += PAGE_SIZE) {
- struct page *p = virt_to_page(start);
+ struct page *p;
+
+ memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
+ p = virt_to_page(start);
ClearPageReserved(p);
init_page_count(p);
__free_page(p);
+ totalram_pages++;
num_physpages++;
}
}
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index f167835db3d..daadf5f8805 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -12,10 +12,11 @@
#include <linux/highmem.h> /* pte_offset_map => kmap_atomic */
#include <linux/bitops.h>
#include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/io-unit.h>
#include <asm/mxcc.h>
@@ -34,13 +35,10 @@
#define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
-void __init
-iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
+static void __init iounit_iommu_init(struct of_device *op)
{
- iopte_t *xpt, *xptend;
struct iounit_struct *iounit;
- struct linux_prom_registers iommu_promregs[PROMREG_MAX];
- struct resource r;
+ iopte_t *xpt, *xptend;
iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
if (!iounit) {
@@ -55,18 +53,13 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
iounit->rotor[1] = IOUNIT_BMAP2_START;
iounit->rotor[2] = IOUNIT_BMAPM_START;
- xpt = NULL;
- if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
- sizeof(iommu_promregs)) != -1) {
- prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
- memset(&r, 0, sizeof(r));
- r.flags = iommu_promregs[2].which_io;
- r.start = iommu_promregs[2].phys_addr;
- xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
+ xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT");
+ if (!xpt) {
+ prom_printf("SUN4D: Cannot map External Page Table.");
+ prom_halt();
}
- if(!xpt) panic("Cannot map External Page Table.");
- sbus->ofdev.dev.archdata.iommu = iounit;
+ op->dev.archdata.iommu = iounit;
iounit->page_table = xpt;
spin_lock_init(&iounit->lock);
@@ -75,6 +68,25 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
iopte_val(*xpt++) = 0;
}
+static int __init iounit_init(void)
+{
+ extern void sun4d_init_sbi_irq(void);
+ struct device_node *dp;
+
+ for_each_node_by_name(dp, "sbi") {
+ struct of_device *op = of_find_device_by_node(dp);
+
+ iounit_iommu_init(op);
+ of_propagate_archdata(op);
+ }
+
+ sun4d_init_sbi_irq();
+
+ return 0;
+}
+
+subsys_initcall(iounit_init);
+
/* One has to hold iounit->lock to call this */
static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
{
@@ -124,10 +136,10 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
return vaddr;
}
-static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long ret, flags;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
spin_lock_irqsave(&iounit->lock, flags);
ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
@@ -135,10 +147,10 @@ static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus
return ret;
}
-static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long flags;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
spin_lock_irqsave(&iounit->lock, flags);
@@ -151,10 +163,10 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus
spin_unlock_irqrestore(&iounit->lock, flags);
}
-static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long flags;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
spin_lock_irqsave(&iounit->lock, flags);
len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
@@ -165,11 +177,11 @@ static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_
spin_unlock_irqrestore(&iounit->lock, flags);
}
-static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long flags;
unsigned long vaddr, len;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
spin_lock_irqsave(&iounit->lock, flags);
while (sz != 0) {
@@ -185,12 +197,12 @@ static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_
}
#ifdef CONFIG_SBUS
-static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
+static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len)
{
+ struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long page, end;
pgprot_t dvma_prot;
iopte_t *iopte;
- struct sbus_bus *sbus;
*pba = addr;
@@ -212,12 +224,8 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
- for_each_sbus(sbus) {
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
- iopte = (iopte_t *)(iounit->page_table + i);
- *iopte = MKIOPTE(__pa(page));
- }
+ iopte = (iopte_t *)(iounit->page_table + i);
+ *iopte = MKIOPTE(__pa(page));
}
addr += PAGE_SIZE;
va += PAGE_SIZE;
@@ -228,23 +236,10 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
return 0;
}
-static void iounit_unmap_dma_area(unsigned long addr, int len)
+static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len)
{
/* XXX Somebody please fill this in */
}
-
-/* XXX We do not pass sbus device here, bad. */
-static struct page *iounit_translate_dvma(unsigned long addr)
-{
- struct sbus_bus *sbus = sbus_root; /* They are all the same */
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
- int i;
- iopte_t *iopte;
-
- i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
- iopte = (iopte_t *)(iounit->page_table + i);
- return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
-}
#endif
static char *iounit_lockarea(char *vaddr, unsigned long len)
@@ -271,54 +266,5 @@ void __init ld_mmu_iounit(void)
#ifdef CONFIG_SBUS
BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
#endif
}
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
- int i, j, k, npages;
- unsigned long rotor, scan, limit;
- unsigned long flags;
- __u32 ret;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
- npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
- i = 0x0213;
- spin_lock_irqsave(&iounit->lock, flags);
-next: j = (i & 15);
- rotor = iounit->rotor[j - 1];
- limit = iounit->limit[j];
- scan = rotor;
-nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
- if (scan + npages > limit) {
- if (limit != rotor) {
- limit = rotor;
- scan = iounit->limit[j - 1];
- goto nexti;
- }
- i >>= 4;
- if (!(i & 15))
- panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
- goto next;
- }
- for (k = 1, scan++; k < npages; k++)
- if (test_bit(scan++, iounit->bmap))
- goto nexti;
- iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
- scan -= npages;
- ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
- for (k = 0; k < npages; k++, scan++)
- set_bit(scan, iounit->bmap);
- spin_unlock_irqrestore(&iounit->lock, flags);
- return ret;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
- int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
- struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
- iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
- return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
-}
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index 4b934270f05..e7a499e3aa3 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -13,10 +13,11 @@
#include <linux/slab.h>
#include <linux/highmem.h> /* pte_offset_map => kmap_atomic */
#include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/mxcc.h>
#include <asm/mbus.h>
@@ -55,30 +56,21 @@ static pgprot_t dvma_prot; /* Consistent mapping pte flags */
#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
#define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ)
-void __init
-iommu_init(int iommund, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
{
- unsigned int impl, vers;
- unsigned long tmp;
struct iommu_struct *iommu;
- struct linux_prom_registers iommu_promregs[PROMREG_MAX];
- struct resource r;
+ unsigned int impl, vers;
unsigned long *bitmap;
+ unsigned long tmp;
iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
if (!iommu) {
prom_printf("Unable to allocate iommu structure\n");
prom_halt();
}
- iommu->regs = NULL;
- if (prom_getproperty(iommund, "reg", (void *) iommu_promregs,
- sizeof(iommu_promregs)) != -1) {
- memset(&r, 0, sizeof(r));
- r.flags = iommu_promregs[0].which_io;
- r.start = iommu_promregs[0].phys_addr;
- iommu->regs = (struct iommu_regs *)
- sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs");
- }
+
+ iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3,
+ "iommu_regs");
if (!iommu->regs) {
prom_printf("Cannot map IOMMU registers\n");
prom_halt();
@@ -128,13 +120,29 @@ iommu_init(int iommund, struct sbus_bus *sbus)
else
iommu->usemap.num_colors = 1;
- printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
- impl, vers, iommu->page_table,
- (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+ printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
+ impl, vers, iommu->page_table,
+ (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+
+ op->dev.archdata.iommu = iommu;
+}
+
+static int __init iommu_init(void)
+{
+ struct device_node *dp;
+
+ for_each_node_by_name(dp, "iommu") {
+ struct of_device *op = of_find_device_by_node(dp);
+
+ sbus_iommu_init(op);
+ of_propagate_archdata(op);
+ }
- sbus->ofdev.dev.archdata.iommu = iommu;
+ return 0;
}
+subsys_initcall(iommu_init);
+
/* This begs to be btfixup-ed by srmmu. */
/* Flush the iotlb entries to ram. */
/* This could be better if we didn't have to flush whole pages. */
@@ -164,9 +172,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
}
}
-static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
+static u32 iommu_get_one(struct device *dev, struct page *page, int npages)
{
- struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu_struct *iommu = dev->archdata.iommu;
int ioptex;
iopte_t *iopte, *iopte0;
unsigned int busa, busa0;
@@ -194,8 +202,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
return busa0;
}
-static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
- struct sbus_bus *sbus)
+static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len)
{
unsigned long off;
int npages;
@@ -205,22 +212,22 @@ static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
off = (unsigned long)vaddr & ~PAGE_MASK;
npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
page = virt_to_page((unsigned long)vaddr & PAGE_MASK);
- busa = iommu_get_one(page, npages, sbus);
+ busa = iommu_get_one(dev, page, npages);
return busa + off;
}
-static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len)
{
- return iommu_get_scsi_one(vaddr, len, sbus);
+ return iommu_get_scsi_one(dev, vaddr, len);
}
-static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len)
{
flush_page_for_dma(0);
- return iommu_get_scsi_one(vaddr, len, sbus);
+ return iommu_get_scsi_one(dev, vaddr, len);
}
-static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len)
{
unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
@@ -228,23 +235,23 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sb
flush_page_for_dma(page);
page += PAGE_SIZE;
}
- return iommu_get_scsi_one(vaddr, len, sbus);
+ return iommu_get_scsi_one(dev, vaddr, len);
}
-static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz)
{
int n;
while (sz != 0) {
--sz;
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
- sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+ sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
sg->dvma_length = (__u32) sg->length;
sg = sg_next(sg);
}
}
-static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz)
{
int n;
@@ -252,13 +259,13 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu
while (sz != 0) {
--sz;
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
- sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+ sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
sg->dvma_length = (__u32) sg->length;
sg = sg_next(sg);
}
}
-static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz)
{
unsigned long page, oldpage = 0;
int n, i;
@@ -283,15 +290,15 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu
}
}
- sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+ sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
sg->dvma_length = (__u32) sg->length;
sg = sg_next(sg);
}
}
-static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
+static void iommu_release_one(struct device *dev, u32 busa, int npages)
{
- struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu_struct *iommu = dev->archdata.iommu;
int ioptex;
int i;
@@ -305,17 +312,17 @@ static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
bit_map_clear(&iommu->usemap, ioptex, npages);
}
-static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
{
unsigned long off;
int npages;
off = vaddr & ~PAGE_MASK;
npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
- iommu_release_one(vaddr & PAGE_MASK, npages, sbus);
+ iommu_release_one(dev, vaddr & PAGE_MASK, npages);
}
-static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
int n;
@@ -323,18 +330,18 @@ static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_b
--sz;
n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
- iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus);
+ iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n);
sg->dvma_address = 0x21212121;
sg = sg_next(sg);
}
}
#ifdef CONFIG_SBUS
-static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
- unsigned long addr, int len)
+static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+ unsigned long addr, int len)
{
+ struct iommu_struct *iommu = dev->archdata.iommu;
unsigned long page, end;
- struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
iopte_t *iopte = iommu->page_table;
iopte_t *first;
int ioptex;
@@ -397,9 +404,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
return 0;
}
-static void iommu_unmap_dma_area(unsigned long busa, int len)
+static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len)
{
- struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
+ struct iommu_struct *iommu = dev->archdata.iommu;
iopte_t *iopte = iommu->page_table;
unsigned long end;
int ioptex = (busa - iommu->start) >> PAGE_SHIFT;
@@ -417,15 +424,6 @@ static void iommu_unmap_dma_area(unsigned long busa, int len)
iommu_invalidate(iommu->regs);
bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT);
}
-
-static struct page *iommu_translate_dvma(unsigned long busa)
-{
- struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
- iopte_t *iopte = iommu->page_table;
-
- iopte += ((busa - iommu->start) >> PAGE_SHIFT);
- return pfn_to_page((iopte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4));
-}
#endif
static char *iommu_lockarea(char *vaddr, unsigned long len)
@@ -461,7 +459,6 @@ void __init ld_mmu_iommu(void)
#ifdef CONFIG_SBUS
BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM);
#endif
if (viking_mxcc_present || srmmu_modtype == HyperSparc) {
diff --git a/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
deleted file mode 100644
index 3701f70fc30..00000000000
--- a/arch/sparc/mm/nosrmmu.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * nosrmmu.c: This file is a bunch of dummies for sun4 compiles,
- * so that it does not need srmmu and avoid ifdefs.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <asm/mbus.h>
-#include <asm/sbus.h>
-
-static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
-
-enum mbus_module srmmu_modtype;
-void *srmmu_nocache_pool;
-
-int vac_cache_size = 0;
-
-static void __init should_not_happen(void)
-{
- prom_printf(shouldnothappen);
- prom_halt();
-}
-
-void __init srmmu_frob_mem_map(unsigned long start_mem)
-{
- should_not_happen();
-}
-
-unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
- should_not_happen();
- return 0;
-}
-
-void __init ld_mmu_srmmu(void)
-{
- should_not_happen();
-}
-
-void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
-{
-}
-
-void srmmu_unmapioaddr(unsigned long virt_addr)
-{
-}
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
- return 0;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
- return 0;
-}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index ee30462598f..6a5d7cabc04 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -31,7 +31,6 @@
#include <asm/mbus.h>
#include <asm/cache.h>
#include <asm/oplib.h>
-#include <asm/sbus.h>
#include <asm/asi.h>
#include <asm/msi.h>
#include <asm/mmu_context.h>
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index d1782f6368b..fe65aeeb394 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -31,7 +31,6 @@
#include <asm/oplib.h>
#include <asm/openprom.h>
#include <asm/mmu_context.h>
-#include <asm/sun4paddr.h>
#include <asm/highmem.h>
#include <asm/btfixup.h>
#include <asm/cacheflush.h>
@@ -52,15 +51,11 @@ extern int num_segmaps, num_contexts;
extern unsigned long page_kernel;
-#ifdef CONFIG_SUN4
-#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
-#else
/* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
* So let's save some cycles and just use that everywhere except for that bootup
* sanity check.
*/
#define SUN4C_VAC_SIZE 65536
-#endif
#define SUN4C_KERNEL_BUCKETS 32
@@ -285,75 +280,32 @@ void __init sun4c_probe_vac(void)
{
sun4c_disable_vac();
- if (ARCH_SUN4) {
- switch (idprom->id_machtype) {
-
- case (SM_SUN4|SM_4_110):
- sun4c_vacinfo.type = VAC_NONE;
- sun4c_vacinfo.num_bytes = 0;
- sun4c_vacinfo.linesize = 0;
- sun4c_vacinfo.do_hwflushes = 0;
- prom_printf("No VAC. Get some bucks and buy a real computer.");
- prom_halt();
- break;
-
- case (SM_SUN4|SM_4_260):
- sun4c_vacinfo.type = VAC_WRITE_BACK;
- sun4c_vacinfo.num_bytes = 128 * 1024;
- sun4c_vacinfo.linesize = 16;
- sun4c_vacinfo.do_hwflushes = 0;
- break;
-
- case (SM_SUN4|SM_4_330):
- sun4c_vacinfo.type = VAC_WRITE_THROUGH;
- sun4c_vacinfo.num_bytes = 128 * 1024;
- sun4c_vacinfo.linesize = 16;
- sun4c_vacinfo.do_hwflushes = 0;
- break;
-
- case (SM_SUN4|SM_4_470):
- sun4c_vacinfo.type = VAC_WRITE_BACK;
- sun4c_vacinfo.num_bytes = 128 * 1024;
- sun4c_vacinfo.linesize = 32;
- sun4c_vacinfo.do_hwflushes = 0;
- break;
-
- default:
- prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
- prom_halt();
- };
+ if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+ /* PROM on SS1 lacks this info, to be super safe we
+ * hard code it here since this arch is cast in stone.
+ */
+ sun4c_vacinfo.num_bytes = 65536;
+ sun4c_vacinfo.linesize = 16;
} else {
- sun4c_vacinfo.type = VAC_WRITE_THROUGH;
+ sun4c_vacinfo.num_bytes =
+ prom_getintdefault(prom_root_node, "vac-size", 65536);
+ sun4c_vacinfo.linesize =
+ prom_getintdefault(prom_root_node, "vac-linesize", 16);
+ }
+ sun4c_vacinfo.do_hwflushes =
+ prom_getintdefault(prom_root_node, "vac-hwflush", 0);
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* PROM on SS1 lacks this info, to be super safe we
- * hard code it here since this arch is cast in stone.
- */
- sun4c_vacinfo.num_bytes = 65536;
- sun4c_vacinfo.linesize = 16;
- } else {
- sun4c_vacinfo.num_bytes =
- prom_getintdefault(prom_root_node, "vac-size", 65536);
- sun4c_vacinfo.linesize =
- prom_getintdefault(prom_root_node, "vac-linesize", 16);
- }
+ if (sun4c_vacinfo.do_hwflushes == 0)
sun4c_vacinfo.do_hwflushes =
- prom_getintdefault(prom_root_node, "vac-hwflush", 0);
-
- if (sun4c_vacinfo.do_hwflushes == 0)
- sun4c_vacinfo.do_hwflushes =
- prom_getintdefault(prom_root_node, "vac_hwflush", 0);
+ prom_getintdefault(prom_root_node, "vac_hwflush", 0);
- if (sun4c_vacinfo.num_bytes != 65536) {
- prom_printf("WEIRD Sun4C VAC cache size, "
- "tell sparclinux@vger.kernel.org");
- prom_halt();
- }
+ if (sun4c_vacinfo.num_bytes != 65536) {
+ prom_printf("WEIRD Sun4C VAC cache size, "
+ "tell sparclinux@vger.kernel.org");
+ prom_halt();
}
- sun4c_vacinfo.num_lines =
- (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
switch (sun4c_vacinfo.linesize) {
case 16:
sun4c_vacinfo.log2lsize = 4;
@@ -447,49 +399,18 @@ static void __init patch_kernel_fault_handler(void)
static void __init sun4c_probe_mmu(void)
{
- if (ARCH_SUN4) {
- switch (idprom->id_machtype) {
- case (SM_SUN4|SM_4_110):
- prom_printf("No support for 4100 yet\n");
- prom_halt();
- num_segmaps = 256;
- num_contexts = 8;
- break;
-
- case (SM_SUN4|SM_4_260):
- /* should be 512 segmaps. when it get fixed */
- num_segmaps = 256;
- num_contexts = 16;
- break;
-
- case (SM_SUN4|SM_4_330):
- num_segmaps = 256;
- num_contexts = 16;
- break;
-
- case (SM_SUN4|SM_4_470):
- /* should be 1024 segmaps. when it get fixed */
- num_segmaps = 256;
- num_contexts = 64;
- break;
- default:
- prom_printf("Invalid SUN4 model\n");
- prom_halt();
- };
+ if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+ /* Hardcode these just to be safe, PROM on SS1 does
+ * not have this info available in the root node.
+ */
+ num_segmaps = 128;
+ num_contexts = 8;
} else {
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* Hardcode these just to be safe, PROM on SS1 does
- * not have this info available in the root node.
- */
- num_segmaps = 128;
- num_contexts = 8;
- } else {
- num_segmaps =
- prom_getintdefault(prom_root_node, "mmu-npmg", 128);
- num_contexts =
- prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
- }
+ num_segmaps =
+ prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+ num_contexts =
+ prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
}
patch_kernel_fault_handler();
}
@@ -501,18 +422,14 @@ void __init sun4c_probe_memerr_reg(void)
int node;
struct linux_prom_registers regs[1];
- if (ARCH_SUN4) {
- sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE);
- } else {
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(prom_root_node, "memory-error");
- if (!node)
- return;
- if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
- return;
- /* hmm I think regs[0].which_io is zero here anyways */
- sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
- }
+ node = prom_getchild(prom_root_node);
+ node = prom_searchsiblings(prom_root_node, "memory-error");
+ if (!node)
+ return;
+ if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
+ return;
+ /* hmm I think regs[0].which_io is zero here anyways */
+ sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
}
static inline void sun4c_init_ss2_cache_bug(void)
@@ -521,7 +438,6 @@ static inline void sun4c_init_ss2_cache_bug(void)
if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
(idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
- (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
/* Whee.. */
printk("SS2 cache bug detected, uncaching trap table page\n");
@@ -532,8 +448,8 @@ static inline void sun4c_init_ss2_cache_bug(void)
}
/* Addr is always aligned on a page boundary for us already. */
-static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
- unsigned long addr, int len)
+static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+ unsigned long addr, int len)
{
unsigned long page, end;
@@ -555,14 +471,7 @@ static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
return 0;
}
-static struct page *sun4c_translate_dvma(unsigned long busa)
-{
- /* Fortunately for us, bus_addr == uncached_virt in sun4c. */
- unsigned long pte = sun4c_get_pte(busa);
- return pfn_to_page(pte & SUN4C_PFN_MASK);
-}
-
-static void sun4c_unmap_dma_area(unsigned long busa, int len)
+static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len)
{
/* Fortunately for us, bus_addr == uncached_virt in sun4c. */
/* XXX Implement this */
@@ -624,11 +533,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
{
unsigned long vaddr;
unsigned char pseg, ctx;
-#ifdef CONFIG_SUN4
- /* sun4/110 and 260 have no kadb. */
- if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) &&
- (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
-#endif
+
for (vaddr = KADB_DEBUGGER_BEGVM;
vaddr < LINUX_OPPROM_ENDVM;
vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -640,9 +545,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
}
}
-#ifdef CONFIG_SUN4
- }
-#endif
+
for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
pseg = sun4c_get_segmap(vaddr);
mmu_entry_pool[pseg].locked = 1;
@@ -1048,14 +951,10 @@ static struct thread_info *sun4c_alloc_thread_info(void)
* so we must flush the cache to guarantee consistency.
*/
sun4c_flush_page(pages);
-#ifndef CONFIG_SUN4
sun4c_flush_page(pages + PAGE_SIZE);
-#endif
sun4c_put_pte(addr, BUCKET_PTE(pages));
-#ifndef CONFIG_SUN4
sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
-#endif
#ifdef CONFIG_DEBUG_STACK_USAGE
memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
@@ -1072,13 +971,11 @@ static void sun4c_free_thread_info(struct thread_info *ti)
/* We are deleting a mapping, so the flush here is mandatory. */
sun4c_flush_page(tiaddr);
-#ifndef CONFIG_SUN4
sun4c_flush_page(tiaddr + PAGE_SIZE);
-#endif
+
sun4c_put_pte(tiaddr, 0);
-#ifndef CONFIG_SUN4
sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
-#endif
+
sun4c_bucket[entry] = BUCKET_EMPTY;
if (entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
@@ -1211,7 +1108,7 @@ static void sun4c_unlockarea(char *vaddr, unsigned long size)
* by implication and fool the page locking code above
* if passed to by mistake.
*/
-static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus)
+static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len)
{
unsigned long page;
@@ -1223,7 +1120,7 @@ static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus
return (__u32)sun4c_lockarea(bufptr, len);
}
-static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
while (sz != 0) {
--sz;
@@ -1233,14 +1130,14 @@ static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *
}
}
-static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus)
+static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len)
{
if (bufptr < sun4c_iobuffer_start)
return; /* On kernel stack or similar, see above */
sun4c_unlockarea((char *)bufptr, len);
}
-static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
{
while (sz != 0) {
--sz;
@@ -2263,7 +2160,6 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile
index 7f5eacfcfbc..8f7e18546c9 100644
--- a/arch/sparc/prom/Makefile
+++ b/arch/sparc/prom/Makefile
@@ -4,5 +4,3 @@
lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
palloc.o ranges.o segment.o console.o printf.o tree.o
-
-lib-$(CONFIG_SUN4) += sun4prom.o
diff --git a/arch/sparc/prom/bootstr.c b/arch/sparc/prom/bootstr.c
index 5a35c768ff7..916831da7e6 100644
--- a/arch/sparc/prom/bootstr.c
+++ b/arch/sparc/prom/bootstr.c
@@ -6,15 +6,12 @@
#include <linux/string.h>
#include <asm/oplib.h>
-#include <asm/sun4prom.h>
#include <linux/init.h>
#define BARG_LEN 256
static char barg_buf[BARG_LEN] = { 0 };
static char fetched __initdata = 0;
-extern linux_sun4_romvec *sun4_romvec;
-
char * __init
prom_getbootargs(void)
{
@@ -28,7 +25,6 @@ prom_getbootargs(void)
switch(prom_vers) {
case PROM_V0:
- case PROM_SUN4:
cp = barg_buf;
/* Start from 1 and go over fd(0,0,0)kernel */
for(iter = 1; iter < 8; iter++) {
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 790057a3461..b3075d73fc1 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/openprom.h>
-#include <asm/sun4prom.h>
#include <asm/oplib.h>
#include <asm/system.h>
#include <linux/string.h>
@@ -30,7 +29,6 @@ prom_nbgetchar(void)
spin_lock_irqsave(&prom_lock, flags);
switch(prom_vers) {
case PROM_V0:
- case PROM_SUN4:
i = (*(romvec->pv_nbgetchar))();
break;
case PROM_V2:
@@ -63,7 +61,6 @@ prom_nbputchar(char c)
spin_lock_irqsave(&prom_lock, flags);
switch(prom_vers) {
case PROM_V0:
- case PROM_SUN4:
i = (*(romvec->pv_nbputchar))(c);
break;
case PROM_V2:
diff --git a/arch/sparc/prom/init.c b/arch/sparc/prom/init.c
index 729f8706694..873217c6d82 100644
--- a/arch/sparc/prom/init.c
+++ b/arch/sparc/prom/init.c
@@ -11,12 +11,10 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
-#include <asm/sun4prom.h>
struct linux_romvec *romvec;
enum prom_major_version prom_vers;
unsigned int prom_rev, prom_prev;
-linux_sun4_romvec *sun4_romvec;
/* The root node of the prom device tree. */
int prom_root_node;
@@ -34,10 +32,6 @@ extern void prom_ranges_init(void);
void __init prom_init(struct linux_romvec *rp)
{
-#ifdef CONFIG_SUN4
- extern struct linux_romvec *sun4_prom_init(void);
- rp = sun4_prom_init();
-#endif
romvec = rp;
switch(romvec->pv_romvers) {
@@ -50,9 +44,6 @@ void __init prom_init(struct linux_romvec *rp)
case 3:
prom_vers = PROM_V3;
break;
- case 40:
- prom_vers = PROM_SUN4;
- break;
default:
prom_printf("PROMLIB: Bad PROM version %d\n",
romvec->pv_romvers);
@@ -76,11 +67,8 @@ void __init prom_init(struct linux_romvec *rp)
prom_ranges_init();
-#ifndef CONFIG_SUN4
- /* SUN4 prints this in sun4_prom_init */
printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
romvec->pv_romvers, prom_rev);
-#endif
/* Initialization successful. */
return;
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index 947f047dc95..fac7899a29c 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <asm/openprom.h>
-#include <asm/sun4prom.h>
#include <asm/oplib.h>
#include <asm/page.h>
@@ -46,15 +45,6 @@ static int __init prom_meminit_v2(void)
return num_ents;
}
-static int __init prom_meminit_sun4(void)
-{
-#ifdef CONFIG_SUN4
- sp_banks[0].base_addr = 0;
- sp_banks[0].num_bytes = *(sun4_romvec->memoryavail);
-#endif
- return 1;
-}
-
static int sp_banks_cmp(const void *a, const void *b)
{
const struct sparc_phys_banks *x = a, *y = b;
@@ -81,10 +71,6 @@ void __init prom_meminit(void)
num_ents = prom_meminit_v2();
break;
- case PROM_SUN4:
- num_ents = prom_meminit_sun4();
- break;
-
default:
break;
}
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index f9b7def35f6..64579a37641 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -9,7 +9,6 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/types.h>
-#include <asm/sbus.h>
#include <asm/system.h>
struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c
deleted file mode 100644
index 00390a2652a..00000000000
--- a/arch/sparc/prom/sun4prom.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 1996 The Australian National University.
- * Copyright (C) 1996 Fujitsu Laboratories Limited
- * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
- * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- *
- * fake a really simple Sun prom for the SUN4
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/sun4prom.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <linux/init.h>
-
-static struct linux_romvec sun4romvec;
-static struct idprom sun4_idprom;
-
-struct property {
- char *name;
- char *value;
- int length;
-};
-
-struct node {
- int level;
- struct property *properties;
-};
-
-struct property null_properties = { NULL, NULL, -1 };
-
-struct property root_properties[] = {
- {"device_type", "cpu", 4},
- {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)},
- {NULL, NULL, -1}
-};
-
-struct node nodes[] = {
- { 0, &null_properties },
- { 0, root_properties },
- { -1,&null_properties }
-};
-
-
-static int no_nextnode(int node)
-{
- if (nodes[node].level == nodes[node+1].level)
- return node+1;
- return -1;
-}
-
-static int no_child(int node)
-{
- if (nodes[node].level == nodes[node+1].level-1)
- return node+1;
- return -1;
-}
-
-static struct property *find_property(int node,char *name)
-{
- struct property *prop = &nodes[node].properties[0];
- while (prop && prop->name) {
- if (strcmp(prop->name,name) == 0) return prop;
- prop++;
- }
- return NULL;
-}
-
-static int no_proplen(int node,char *name)
-{
- struct property *prop = find_property(node,name);
- if (prop) return prop->length;
- return -1;
-}
-
-static int no_getprop(int node,char *name,char *value)
-{
- struct property *prop = find_property(node,name);
- if (prop) {
- memcpy(value,prop->value,prop->length);
- return 1;
- }
- return -1;
-}
-
-static int no_setprop(int node,char *name,char *value,int len)
-{
- return -1;
-}
-
-static char *no_nextprop(int node,char *name)
-{
- struct property *prop = find_property(node,name);
- if (prop) return prop[1].name;
- return NULL;
-}
-
-static struct linux_nodeops sun4_nodeops = {
- no_nextnode,
- no_child,
- no_proplen,
- no_getprop,
- no_setprop,
- no_nextprop
-};
-
-static int synch_hook;
-
-struct linux_romvec * __init sun4_prom_init(void)
-{
- int i;
- unsigned char x;
- char *p;
-
- p = (char *)&sun4_idprom;
- for (i = 0; i < sizeof(sun4_idprom); i++) {
- __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) :
- "r" (AC_IDPROM + i), "i" (ASI_CONTROL));
- *p++ = x;
- }
-
- memset(&sun4romvec,0,sizeof(sun4romvec));
-
- sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR;
-
- sun4romvec.pv_romvers = 40;
- sun4romvec.pv_nodeops = &sun4_nodeops;
- sun4romvec.pv_reboot = sun4_romvec->reboot;
- sun4romvec.pv_abort = sun4_romvec->abortentry;
- sun4romvec.pv_halt = sun4_romvec->exittomon;
- sun4romvec.pv_synchook = (void (**)(void))&synch_hook;
- sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap;
- sun4romvec.pv_v0bootargs = sun4_romvec->bootParam;
- sun4romvec.pv_nbgetchar = sun4_romvec->mayget;
- sun4romvec.pv_nbputchar = sun4_romvec->mayput;
- sun4romvec.pv_stdin = sun4_romvec->insource;
- sun4romvec.pv_stdout = sun4_romvec->outsink;
-
- /*
- * We turn on the LEDs to let folks without monitors or
- * terminals know we booted. Nothing too fancy now. They
- * are all on, except for LED 5, which blinks. When we
- * have more time, we can teach the penguin to say "By your
- * command" or "Activating turbo boost, Michael". :-)
- */
- sun4_romvec->setLEDs(NULL);
-
- printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n",
- sun4_romvec->monid,
- sun4_romvec->romvecversion);
-
- return &sun4romvec;
-}
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 36b4b7ab9cf..5446e2a499b 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -18,6 +18,13 @@ config SPARC64
select HAVE_ARCH_KGDB
select USE_GENERIC_SMP_HELPERS if SMP
select HAVE_ARCH_TRACEHOOK
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select RTC_CLASS
+ select RTC_DRV_M48T59
+ select RTC_DRV_CMOS
+ select RTC_DRV_BQ4802
+ select RTC_DRV_SUN4V
+ select RTC_DRV_STARFIRE
config GENERIC_TIME
bool
@@ -31,6 +38,11 @@ config GENERIC_CLOCKEVENTS
bool
default y
+config GENERIC_GPIO
+ bool
+ help
+ Generic GPIO API support
+
config 64BIT
def_bool y
@@ -185,6 +197,17 @@ config US2E_FREQ
If in doubt, say N.
+config US3_MC
+ tristate "UltraSPARC-III Memory Controller driver"
+ default y
+ help
+ This adds a driver for the UltraSPARC-III memory controller.
+ Loading this driver allows exact mnemonic strings to be
+ printed in the event of a memory error, so that the faulty DIMM
+ on the motherboard can be matched to the error.
+
+ If in doubt, say Y, as this information can be very useful.
+
# Global things across all Sun machines.
config GENERIC_LOCKBREAK
bool
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index b785a395b12..c7214abc0d8 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -7,7 +7,7 @@
# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
#
-CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -m64
+CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
# Undefine sparc when processing vmlinux.lds - it is used
# And teach CPP we are doing 64 bit builds (for this case)
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 418b5782096..c0b8009ab19 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -7,16 +7,16 @@ EXTRA_CFLAGS := -Werror
extra-y := head.o init_task.o vmlinux.lds
-obj-y := process.o setup.o cpu.o idprom.o \
+obj-y := process.o setup.o cpu.o idprom.o reboot.o \
traps.o auxio.o una_asm.o sysfs.o iommu.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
- unaligned.o central.o pci.o starfire.o \
- power.o sbus.o sparc64_ksyms.o chmc.o \
+ unaligned.o central.o starfire.o \
+ power.o sbus.o sparc64_ksyms.o ebus.o \
visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI) += ebus.o pci_common.o \
+obj-$(CONFIG_PCI) += pci.o pci_common.o psycho_common.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
obj-$(CONFIG_PCI_MSI) += pci_msi.o
@@ -25,6 +25,7 @@ obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
+obj-$(CONFIG_US3_MC) += chmc.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
obj-$(CONFIG_AUDIT) += audit.o
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index dd5c7bf8761..858beda8652 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -109,7 +109,7 @@ void auxio_set_lte(int on)
}
}
-static struct of_device_id auxio_match[] = {
+static struct of_device_id __initdata auxio_match[] = {
{
.name = "auxio",
},
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index f2e87d0d7e1..05f1c916db0 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -1,461 +1,268 @@
/* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
- * Copyright (C) 1997, 1999 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
-#include <asm/page.h>
#include <asm/fhc.h>
-#include <asm/starfire.h>
-
-static struct linux_central *central_bus = NULL;
-static struct linux_fhc *fhc_list = NULL;
+#include <asm/upa.h>
+
+struct clock_board {
+ void __iomem *clock_freq_regs;
+ void __iomem *clock_regs;
+ void __iomem *clock_ver_reg;
+ int num_slots;
+ struct resource leds_resource;
+ struct platform_device leds_pdev;
+};
+
+struct fhc {
+ void __iomem *pregs;
+ bool central;
+ bool jtag_master;
+ int board_num;
+ struct resource leds_resource;
+ struct platform_device leds_pdev;
+};
+
+static int __devinit clock_board_calc_nslots(struct clock_board *p)
+{
+ u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
-#define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child)
+ switch (reg) {
+ case 0x40:
+ return 16;
-static void central_probe_failure(int line)
-{
- prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n",
- line);
- prom_halt();
-}
+ case 0xc0:
+ return 8;
-static void central_ranges_init(struct linux_central *central)
-{
- struct device_node *dp = central->prom_node;
- const void *pval;
- int len;
-
- central->num_central_ranges = 0;
- pval = of_get_property(dp, "ranges", &len);
- if (pval) {
- memcpy(central->central_ranges, pval, len);
- central->num_central_ranges =
- (len / sizeof(struct linux_prom_ranges));
+ case 0x80:
+ reg = 0;
+ if (p->clock_ver_reg)
+ reg = upa_readb(p->clock_ver_reg);
+ if (reg) {
+ if (reg & 0x80)
+ return 4;
+ else
+ return 5;
+ }
+ /* Fallthrough */
+ default:
+ return 4;
}
}
-static void fhc_ranges_init(struct linux_fhc *fhc)
+static int __devinit clock_board_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct device_node *dp = fhc->prom_node;
- const void *pval;
- int len;
-
- fhc->num_fhc_ranges = 0;
- pval = of_get_property(dp, "ranges", &len);
- if (pval) {
- memcpy(fhc->fhc_ranges, pval, len);
- fhc->num_fhc_ranges =
- (len / sizeof(struct linux_prom_ranges));
- }
-}
+ struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
-/* Range application routines are exported to various drivers,
- * so do not __init this.
- */
-static void adjust_regs(struct linux_prom_registers *regp, int nregs,
- struct linux_prom_ranges *rangep, int nranges)
-{
- int regc, rngc;
-
- for (regc = 0; regc < nregs; regc++) {
- for (rngc = 0; rngc < nranges; rngc++)
- if (regp[regc].which_io == rangep[rngc].ot_child_space)
- break; /* Fount it */
- if (rngc == nranges) /* oops */
- central_probe_failure(__LINE__);
- regp[regc].which_io = rangep[rngc].ot_parent_space;
- regp[regc].phys_addr -= rangep[rngc].ot_child_base;
- regp[regc].phys_addr += rangep[rngc].ot_parent_base;
+ if (!p) {
+ printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
+ goto out;
}
-}
-/* Apply probed fhc ranges to registers passed, if no ranges return. */
-static void apply_fhc_ranges(struct linux_fhc *fhc,
- struct linux_prom_registers *regs,
- int nregs)
-{
- if (fhc->num_fhc_ranges)
- adjust_regs(regs, nregs, fhc->fhc_ranges,
- fhc->num_fhc_ranges);
-}
+ p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "clock_board_freq");
+ if (!p->clock_freq_regs) {
+ printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n");
+ goto out_free;
+ }
-/* Apply probed central ranges to registers passed, if no ranges return. */
-static void apply_central_ranges(struct linux_central *central,
- struct linux_prom_registers *regs, int nregs)
-{
- if (central->num_central_ranges)
- adjust_regs(regs, nregs, central->central_ranges,
- central->num_central_ranges);
-}
+ p->clock_regs = of_ioremap(&op->resource[1], 0,
+ resource_size(&op->resource[1]),
+ "clock_board_regs");
+ if (!p->clock_regs) {
+ printk(KERN_ERR "clock_board: Cannot map clock_regs\n");
+ goto out_unmap_clock_freq_regs;
+ }
-static void * __init central_alloc_bootmem(unsigned long size)
-{
- void *ret;
+ if (op->resource[2].flags) {
+ p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
+ resource_size(&op->resource[2]),
+ "clock_ver_reg");
+ if (!p->clock_ver_reg) {
+ printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n");
+ goto out_unmap_clock_regs;
+ }
+ }
- ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
- if (ret != NULL)
- memset(ret, 0, size);
+ p->num_slots = clock_board_calc_nslots(p);
- return ret;
-}
+ p->leds_resource.start = (unsigned long)
+ (p->clock_regs + CLOCK_CTRL);
+ p->leds_resource.end = p->leds_resource.end;
+ p->leds_resource.name = "leds";
-static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
-{
- unsigned long ret = ((unsigned long) r->which_io) << 32;
+ p->leds_pdev.name = "sunfire-clockboard-leds";
+ p->leds_pdev.resource = &p->leds_resource;
+ p->leds_pdev.num_resources = 1;
+ p->leds_pdev.dev.parent = &op->dev;
- return ret | (unsigned long) r->phys_addr;
-}
-
-static void __init probe_other_fhcs(void)
-{
- struct device_node *dp;
- const struct linux_prom64_registers *fpregs;
-
- for_each_node_by_name(dp, "fhc") {
- struct linux_fhc *fhc;
- int board;
- u32 tmp;
-
- if (dp->parent &&
- dp->parent->parent != NULL)
- continue;
-
- fhc = (struct linux_fhc *)
- central_alloc_bootmem(sizeof(struct linux_fhc));
- if (fhc == NULL)
- central_probe_failure(__LINE__);
-
- /* Link it into the FHC chain. */
- fhc->next = fhc_list;
- fhc_list = fhc;
-
- /* Toplevel FHCs have no parent. */
- fhc->parent = NULL;
-
- fhc->prom_node = dp;
- fhc_ranges_init(fhc);
-
- /* Non-central FHC's have 64-bit OBP format registers. */
- fpregs = of_get_property(dp, "reg", NULL);
- if (!fpregs)
- central_probe_failure(__LINE__);
-
- /* Only central FHC needs special ranges applied. */
- fhc->fhc_regs.pregs = fpregs[0].phys_addr;
- fhc->fhc_regs.ireg = fpregs[1].phys_addr;
- fhc->fhc_regs.ffregs = fpregs[2].phys_addr;
- fhc->fhc_regs.sregs = fpregs[3].phys_addr;
- fhc->fhc_regs.uregs = fpregs[4].phys_addr;
- fhc->fhc_regs.tregs = fpregs[5].phys_addr;
-
- board = of_getintprop_default(dp, "board#", -1);
- fhc->board = board;
-
- tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
- if ((tmp & FHC_JTAG_CTRL_MENAB) != 0)
- fhc->jtag_master = 1;
- else
- fhc->jtag_master = 0;
-
- tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
- printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
- board,
- (tmp & FHC_ID_VERS) >> 28,
- (tmp & FHC_ID_PARTID) >> 12,
- (tmp & FHC_ID_MANUF) >> 1,
- (fhc->jtag_master ? "(JTAG Master)" : ""));
-
- /* This bit must be set in all non-central FHC's in
- * the system. When it is clear, this identifies
- * the central board.
- */
- tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
- tmp |= FHC_CONTROL_IXIST;
- upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ err = platform_device_register(&p->leds_pdev);
+ if (err) {
+ printk(KERN_ERR "clock_board: Could not register LEDS "
+ "platform device\n");
+ goto out_unmap_clock_ver_reg;
}
-}
-static void probe_clock_board(struct linux_central *central,
- struct linux_fhc *fhc,
- struct device_node *fp)
-{
- struct device_node *dp;
- struct linux_prom_registers cregs[3];
- const struct linux_prom_registers *pr;
- int nslots, tmp, nregs;
-
- dp = fp->child;
- while (dp) {
- if (!strcmp(dp->name, "clock-board"))
- break;
- dp = dp->sibling;
- }
- if (!dp)
- central_probe_failure(__LINE__);
+ printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
+ p->num_slots);
- pr = of_get_property(dp, "reg", &nregs);
- if (!pr)
- central_probe_failure(__LINE__);
+ err = 0;
+out:
+ return err;
- memcpy(cregs, pr, nregs);
- nregs /= sizeof(struct linux_prom_registers);
+out_unmap_clock_ver_reg:
+ if (p->clock_ver_reg)
+ of_iounmap(&op->resource[2], p->clock_ver_reg,
+ resource_size(&op->resource[2]));
- apply_fhc_ranges(fhc, &cregs[0], nregs);
- apply_central_ranges(central, &cregs[0], nregs);
- central->cfreg = prom_reg_to_paddr(&cregs[0]);
- central->clkregs = prom_reg_to_paddr(&cregs[1]);
+out_unmap_clock_regs:
+ of_iounmap(&op->resource[1], p->clock_regs,
+ resource_size(&op->resource[1]));
- if (nregs == 2)
- central->clkver = 0UL;
- else
- central->clkver = prom_reg_to_paddr(&cregs[2]);
+out_unmap_clock_freq_regs:
+ of_iounmap(&op->resource[0], p->clock_freq_regs,
+ resource_size(&op->resource[0]));
- tmp = upa_readb(central->clkregs + CLOCK_STAT1);
- tmp &= 0xc0;
- switch(tmp) {
- case 0x40:
- nslots = 16;
- break;
- case 0xc0:
- nslots = 8;
- break;
- case 0x80:
- if (central->clkver != 0UL &&
- upa_readb(central->clkver) != 0) {
- if ((upa_readb(central->clkver) & 0x80) != 0)
- nslots = 4;
- else
- nslots = 5;
- break;
- }
- default:
- nslots = 4;
- break;
- };
- central->slots = nslots;
- printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
- central->slots, upa_readb(central->cfreg),
- (central->clkver ? upa_readb(central->clkver) : 0x00));
+out_free:
+ kfree(p);
+ goto out;
}
-static void ZAP(unsigned long iclr, unsigned long imap)
+static struct of_device_id __initdata clock_board_match[] = {
+ {
+ .name = "clock-board",
+ },
+ {},
+};
+
+static struct of_platform_driver clock_board_driver = {
+ .match_table = clock_board_match,
+ .probe = clock_board_probe,
+ .driver = {
+ .name = "clock_board",
+ },
+};
+
+static int __devinit fhc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- u32 imap_tmp;
-
- upa_writel(0, iclr);
- upa_readl(iclr);
- imap_tmp = upa_readl(imap);
- imap_tmp &= ~(0x80000000);
- upa_writel(imap_tmp, imap);
- upa_readl(imap);
-}
+ struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
+ u32 reg;
-static void init_all_fhc_hw(void)
-{
- struct linux_fhc *fhc;
-
- for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) {
- u32 tmp;
-
- /* Clear all of the interrupt mapping registers
- * just in case OBP left them in a foul state.
- */
- ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR,
- fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP);
- ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR,
- fhc->fhc_regs.sregs + FHC_SREGS_IMAP);
- ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR,
- fhc->fhc_regs.uregs + FHC_UREGS_IMAP);
- ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR,
- fhc->fhc_regs.tregs + FHC_TREGS_IMAP);
-
- /* Setup FHC control register. */
- tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-
- /* All non-central boards have this bit set. */
- if (! IS_CENTRAL_FHC(fhc))
- tmp |= FHC_CONTROL_IXIST;
-
- /* For all FHCs, clear the firmware synchronization
- * line and both low power mode enables.
- */
- tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF |
- FHC_CONTROL_SLINE);
-
- upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
- upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ if (!p) {
+ printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
+ goto out;
}
-}
+ if (!strcmp(op->node->parent->name, "central"))
+ p->central = true;
-void __init central_probe(void)
-{
- struct linux_prom_registers fpregs[6];
- const struct linux_prom_registers *pr;
- struct linux_fhc *fhc;
- struct device_node *dp, *fp;
- int err;
-
- dp = of_find_node_by_name(NULL, "central");
- if (!dp) {
- if (this_is_starfire)
- starfire_cpu_setup();
- return;
+ p->pregs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "fhc_pregs");
+ if (!p->pregs) {
+ printk(KERN_ERR "fhc: Cannot map pregs\n");
+ goto out_free;
}
- /* Ok we got one, grab some memory for software state. */
- central_bus = (struct linux_central *)
- central_alloc_bootmem(sizeof(struct linux_central));
- if (central_bus == NULL)
- central_probe_failure(__LINE__);
-
- fhc = (struct linux_fhc *)
- central_alloc_bootmem(sizeof(struct linux_fhc));
- if (fhc == NULL)
- central_probe_failure(__LINE__);
-
- /* First init central. */
- central_bus->child = fhc;
- central_bus->prom_node = dp;
- central_ranges_init(central_bus);
-
- /* And then central's FHC. */
- fhc->next = fhc_list;
- fhc_list = fhc;
-
- fhc->parent = central_bus;
- fp = dp->child;
- while (fp) {
- if (!strcmp(fp->name, "fhc"))
- break;
- fp = fp->sibling;
+ if (p->central) {
+ reg = upa_readl(p->pregs + FHC_PREGS_BSR);
+ p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
+ } else {
+ p->board_num = of_getintprop_default(op->node, "board#", -1);
+ if (p->board_num == -1) {
+ printk(KERN_ERR "fhc: No board# property\n");
+ goto out_unmap_pregs;
+ }
+ if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
+ p->jtag_master = true;
}
- if (!fp)
- central_probe_failure(__LINE__);
-
- fhc->prom_node = fp;
- fhc_ranges_init(fhc);
-
- /* Now, map in FHC register set. */
- pr = of_get_property(fp, "reg", NULL);
- if (!pr)
- central_probe_failure(__LINE__);
- memcpy(fpregs, pr, sizeof(fpregs));
-
- apply_central_ranges(central_bus, &fpregs[0], 6);
-
- fhc->fhc_regs.pregs = prom_reg_to_paddr(&fpregs[0]);
- fhc->fhc_regs.ireg = prom_reg_to_paddr(&fpregs[1]);
- fhc->fhc_regs.ffregs = prom_reg_to_paddr(&fpregs[2]);
- fhc->fhc_regs.sregs = prom_reg_to_paddr(&fpregs[3]);
- fhc->fhc_regs.uregs = prom_reg_to_paddr(&fpregs[4]);
- fhc->fhc_regs.tregs = prom_reg_to_paddr(&fpregs[5]);
-
- /* Obtain board number from board status register, Central's
- * FHC lacks "board#" property.
- */
- err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR);
- fhc->board = (((err >> 16) & 0x01) |
- ((err >> 12) & 0x0e));
-
- fhc->jtag_master = 0;
-
- /* Attach the clock board registers for CENTRAL. */
- probe_clock_board(central_bus, fhc, fp);
-
- err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
- printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
- fhc->board,
- ((err & FHC_ID_VERS) >> 28),
- ((err & FHC_ID_PARTID) >> 12),
- ((err & FHC_ID_MANUF) >> 1));
-
- probe_other_fhcs();
-
- init_all_fhc_hw();
-}
-static inline void fhc_ledblink(struct linux_fhc *fhc, int on)
-{
- u32 tmp;
+ if (!p->central) {
+ p->leds_resource.start = (unsigned long)
+ (p->pregs + FHC_PREGS_CTRL);
+ p->leds_resource.end = p->leds_resource.end;
+ p->leds_resource.name = "leds";
+
+ p->leds_pdev.name = "sunfire-fhc-leds";
+ p->leds_pdev.resource = &p->leds_resource;
+ p->leds_pdev.num_resources = 1;
+ p->leds_pdev.dev.parent = &op->dev;
+
+ err = platform_device_register(&p->leds_pdev);
+ if (err) {
+ printk(KERN_ERR "fhc: Could not register LEDS "
+ "platform device\n");
+ goto out_unmap_pregs;
+ }
+ }
+ reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
- tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ if (!p->central)
+ reg |= FHC_CONTROL_IXIST;
- /* NOTE: reverse logic on this bit */
- if (on)
- tmp &= ~(FHC_CONTROL_RLED);
- else
- tmp |= FHC_CONTROL_RLED;
- tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
+ reg &= ~(FHC_CONTROL_AOFF |
+ FHC_CONTROL_BOFF |
+ FHC_CONTROL_SLINE);
- upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
- upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-}
+ upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
+ upa_readl(p->pregs + FHC_PREGS_CTRL);
-static inline void central_ledblink(struct linux_central *central, int on)
-{
- u8 tmp;
-
- tmp = upa_readb(central->clkregs + CLOCK_CTRL);
+ reg = upa_readl(p->pregs + FHC_PREGS_ID);
+ printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n",
+ p->board_num,
+ (reg & FHC_ID_VERS) >> 28,
+ (reg & FHC_ID_PARTID) >> 12,
+ (reg & FHC_ID_MANUF) >> 1,
+ (p->jtag_master ?
+ "(JTAG Master)" :
+ (p->central ? "(Central)" : "")));
- /* NOTE: reverse logic on this bit */
- if (on)
- tmp &= ~(CLOCK_CTRL_RLED);
- else
- tmp |= CLOCK_CTRL_RLED;
+ err = 0;
- upa_writeb(tmp, central->clkregs + CLOCK_CTRL);
- upa_readb(central->clkregs + CLOCK_CTRL);
-}
+out:
+ return err;
-static struct timer_list sftimer;
-static int led_state;
+out_unmap_pregs:
+ of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
-static void sunfire_timer(unsigned long __ignored)
-{
- struct linux_fhc *fhc;
-
- central_ledblink(central_bus, led_state);
- for (fhc = fhc_list; fhc != NULL; fhc = fhc->next)
- if (! IS_CENTRAL_FHC(fhc))
- fhc_ledblink(fhc, led_state);
- led_state = ! led_state;
- sftimer.expires = jiffies + (HZ >> 1);
- add_timer(&sftimer);
+out_free:
+ kfree(p);
+ goto out;
}
-/* After PCI/SBUS busses have been probed, this is called to perform
- * final initialization of all FireHose Controllers in the system.
- */
-void firetruck_init(void)
+static struct of_device_id __initdata fhc_match[] = {
+ {
+ .name = "fhc",
+ },
+ {},
+};
+
+static struct of_platform_driver fhc_driver = {
+ .match_table = fhc_match,
+ .probe = fhc_probe,
+ .driver = {
+ .name = "fhc",
+ },
+};
+
+static int __init sunfire_init(void)
{
- struct linux_central *central = central_bus;
- u8 ctrl;
-
- /* No central bus, nothing to do. */
- if (central == NULL)
- return;
-
- /* OBP leaves it on, turn it off so clock board timer LED
- * is in sync with FHC ones.
- */
- ctrl = upa_readb(central->clkregs + CLOCK_CTRL);
- ctrl &= ~(CLOCK_CTRL_RLED);
- upa_writeb(ctrl, central->clkregs + CLOCK_CTRL);
-
- led_state = 0;
- init_timer(&sftimer);
- sftimer.data = 0;
- sftimer.function = &sunfire_timer;
- sftimer.expires = jiffies + (HZ >> 1);
- add_timer(&sftimer);
+ (void) of_register_driver(&fhc_driver, &of_platform_bus_type);
+ (void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
+ return 0;
}
+
+subsys_initcall(sunfire_init);
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 6d4f02e8a4c..3b9f4d6e14a 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -1,6 +1,6 @@
-/* memctrlr.c: Driver for UltraSPARC-III memory controller.
+/* chmc.c: Driver for UltraSPARC-III memory controller.
*
- * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -13,45 +13,64 @@
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/spitfire.h>
#include <asm/chmctrl.h>
#include <asm/cpudata.h>
#include <asm/oplib.h>
#include <asm/prom.h>
+#include <asm/head.h>
#include <asm/io.h>
+#include <asm/memctrl.h>
+
+#define DRV_MODULE_NAME "chmc"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "0.2"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("UltraSPARC-III memory controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static int mc_type;
+#define MC_TYPE_SAFARI 1
+#define MC_TYPE_JBUS 2
+
+static dimm_printer_t us3mc_dimm_printer;
#define CHMCTRL_NDGRPS 2
#define CHMCTRL_NDIMMS 4
-#define DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
+#define CHMC_DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
/* OBP memory-layout property format. */
-struct obp_map {
+struct chmc_obp_map {
unsigned char dimm_map[144];
unsigned char pin_map[576];
};
#define DIMM_LABEL_SZ 8
-struct obp_mem_layout {
+struct chmc_obp_mem_layout {
/* One max 8-byte string label per DIMM. Usually
* this matches the label on the motherboard where
* that DIMM resides.
*/
- char dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ];
+ char dimm_labels[CHMC_DIMMS_PER_MC][DIMM_LABEL_SZ];
/* If symmetric use map[0], else it is
* asymmetric and map[1] should be used.
*/
- char symmetric;
+ char symmetric;
- struct obp_map map[2];
+ struct chmc_obp_map map[2];
};
#define CHMCTRL_NBANKS 4
-struct bank_info {
- struct mctrl_info *mp;
+struct chmc_bank_info {
+ struct chmc *p;
int bank_id;
u64 raw_reg;
@@ -65,28 +84,406 @@ struct bank_info {
unsigned long size;
};
-struct mctrl_info {
- struct list_head list;
- int portid;
+struct chmc {
+ struct list_head list;
+ int portid;
+
+ struct chmc_obp_mem_layout layout_prop;
+ int layout_size;
+
+ void __iomem *regs;
- struct obp_mem_layout layout_prop;
- int layout_size;
+ u64 timing_control1;
+ u64 timing_control2;
+ u64 timing_control3;
+ u64 timing_control4;
+ u64 memaddr_control;
- void __iomem *regs;
+ struct chmc_bank_info logical_banks[CHMCTRL_NBANKS];
+};
+
+#define JBUSMC_REGS_SIZE 8
+
+#define JB_MC_REG1_DIMM2_BANK3 0x8000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK1 0x4000000000000000UL
+#define JB_MC_REG1_DIMM2_BANK2 0x2000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK0 0x1000000000000000UL
+#define JB_MC_REG1_XOR 0x0000010000000000UL
+#define JB_MC_REG1_ADDR_GEN_2 0x000000e000000000UL
+#define JB_MC_REG1_ADDR_GEN_2_SHIFT 37
+#define JB_MC_REG1_ADDR_GEN_1 0x0000001c00000000UL
+#define JB_MC_REG1_ADDR_GEN_1_SHIFT 34
+#define JB_MC_REG1_INTERLEAVE 0x0000000001800000UL
+#define JB_MC_REG1_INTERLEAVE_SHIFT 23
+#define JB_MC_REG1_DIMM2_PTYPE 0x0000000000200000UL
+#define JB_MC_REG1_DIMM2_PTYPE_SHIFT 21
+#define JB_MC_REG1_DIMM1_PTYPE 0x0000000000100000UL
+#define JB_MC_REG1_DIMM1_PTYPE_SHIFT 20
+
+#define PART_TYPE_X8 0
+#define PART_TYPE_X4 1
+
+#define INTERLEAVE_NONE 0
+#define INTERLEAVE_SAME 1
+#define INTERLEAVE_INTERNAL 2
+#define INTERLEAVE_BOTH 3
+
+#define ADDR_GEN_128MB 0
+#define ADDR_GEN_256MB 1
+#define ADDR_GEN_512MB 2
+#define ADDR_GEN_1GB 3
+
+#define JB_NUM_DIMM_GROUPS 2
+#define JB_NUM_DIMMS_PER_GROUP 2
+#define JB_NUM_DIMMS (JB_NUM_DIMM_GROUPS * JB_NUM_DIMMS_PER_GROUP)
+
+struct jbusmc_obp_map {
+ unsigned char dimm_map[18];
+ unsigned char pin_map[144];
+};
+
+struct jbusmc_obp_mem_layout {
+ /* One max 8-byte string label per DIMM. Usually
+ * this matches the label on the motherboard where
+ * that DIMM resides.
+ */
+ char dimm_labels[JB_NUM_DIMMS][DIMM_LABEL_SZ];
+
+ /* If symmetric use map[0], else it is
+ * asymmetric and map[1] should be used.
+ */
+ char symmetric;
+
+ struct jbusmc_obp_map map;
+
+ char _pad;
+};
- u64 timing_control1;
- u64 timing_control2;
- u64 timing_control3;
- u64 timing_control4;
- u64 memaddr_control;
+struct jbusmc_dimm_group {
+ struct jbusmc *controller;
+ int index;
+ u64 base_addr;
+ u64 size;
+};
- struct bank_info logical_banks[CHMCTRL_NBANKS];
+struct jbusmc {
+ void __iomem *regs;
+ u64 mc_reg_1;
+ u32 portid;
+ struct jbusmc_obp_mem_layout layout;
+ int layout_len;
+ int num_dimm_groups;
+ struct jbusmc_dimm_group dimm_groups[JB_NUM_DIMM_GROUPS];
+ struct list_head list;
};
+static DEFINE_SPINLOCK(mctrl_list_lock);
static LIST_HEAD(mctrl_list);
+static void mc_list_add(struct list_head *list)
+{
+ spin_lock(&mctrl_list_lock);
+ list_add(list, &mctrl_list);
+ spin_unlock(&mctrl_list_lock);
+}
+
+static void mc_list_del(struct list_head *list)
+{
+ spin_lock(&mctrl_list_lock);
+ list_del_init(list);
+ spin_unlock(&mctrl_list_lock);
+}
+
+#define SYNDROME_MIN -1
+#define SYNDROME_MAX 144
+
+/* Covert syndrome code into the way the bits are positioned
+ * on the bus.
+ */
+static int syndrome_to_qword_code(int syndrome_code)
+{
+ if (syndrome_code < 128)
+ syndrome_code += 16;
+ else if (syndrome_code < 128 + 9)
+ syndrome_code -= (128 - 7);
+ else if (syndrome_code < (128 + 9 + 3))
+ syndrome_code -= (128 + 9 - 4);
+ else
+ syndrome_code -= (128 + 9 + 3);
+ return syndrome_code;
+}
+
+/* All this magic has to do with how a cache line comes over the wire
+ * on Safari and JBUS. A 64-bit line comes over in 1 or more quadword
+ * cycles, each of which transmit ECC/MTAG info as well as the actual
+ * data.
+ */
+#define L2_LINE_SIZE 64
+#define L2_LINE_ADDR_MSK (L2_LINE_SIZE - 1)
+#define QW_PER_LINE 4
+#define QW_BYTES (L2_LINE_SIZE / QW_PER_LINE)
+#define QW_BITS 144
+#define SAFARI_LAST_BIT (576 - 1)
+#define JBUS_LAST_BIT (144 - 1)
+
+static void get_pin_and_dimm_str(int syndrome_code, unsigned long paddr,
+ int *pin_p, char **dimm_str_p, void *_prop,
+ int base_dimm_offset)
+{
+ int qword_code = syndrome_to_qword_code(syndrome_code);
+ int cache_line_offset;
+ int offset_inverse;
+ int dimm_map_index;
+ int map_val;
+
+ if (mc_type == MC_TYPE_JBUS) {
+ struct jbusmc_obp_mem_layout *p = _prop;
+
+ /* JBUS */
+ cache_line_offset = qword_code;
+ offset_inverse = (JBUS_LAST_BIT - cache_line_offset);
+ dimm_map_index = offset_inverse / 8;
+ map_val = p->map.dimm_map[dimm_map_index];
+ map_val = ((map_val >> ((7 - (offset_inverse & 7)))) & 1);
+ *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+ *pin_p = p->map.pin_map[cache_line_offset];
+ } else {
+ struct chmc_obp_mem_layout *p = _prop;
+ struct chmc_obp_map *mp;
+ int qword;
+
+ /* Safari */
+ if (p->symmetric)
+ mp = &p->map[0];
+ else
+ mp = &p->map[1];
+
+ qword = (paddr & L2_LINE_ADDR_MSK) / QW_BYTES;
+ cache_line_offset = ((3 - qword) * QW_BITS) + qword_code;
+ offset_inverse = (SAFARI_LAST_BIT - cache_line_offset);
+ dimm_map_index = offset_inverse >> 2;
+ map_val = mp->dimm_map[dimm_map_index];
+ map_val = ((map_val >> ((3 - (offset_inverse & 3)) << 1)) & 0x3);
+ *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+ *pin_p = mp->pin_map[cache_line_offset];
+ }
+}
+
+static struct jbusmc_dimm_group *jbusmc_find_dimm_group(unsigned long phys_addr)
+{
+ struct jbusmc *p;
+
+ list_for_each_entry(p, &mctrl_list, list) {
+ int i;
+
+ for (i = 0; i < p->num_dimm_groups; i++) {
+ struct jbusmc_dimm_group *dp = &p->dimm_groups[i];
+
+ if (phys_addr < dp->base_addr ||
+ (dp->base_addr + dp->size) <= phys_addr)
+ continue;
+
+ return dp;
+ }
+ }
+ return NULL;
+}
+
+static int jbusmc_print_dimm(int syndrome_code,
+ unsigned long phys_addr,
+ char *buf, int buflen)
+{
+ struct jbusmc_obp_mem_layout *prop;
+ struct jbusmc_dimm_group *dp;
+ struct jbusmc *p;
+ int first_dimm;
+
+ dp = jbusmc_find_dimm_group(phys_addr);
+ if (dp == NULL ||
+ syndrome_code < SYNDROME_MIN ||
+ syndrome_code > SYNDROME_MAX) {
+ buf[0] = '?';
+ buf[1] = '?';
+ buf[2] = '?';
+ buf[3] = '\0';
+ }
+ p = dp->controller;
+ prop = &p->layout;
+
+ first_dimm = dp->index * JB_NUM_DIMMS_PER_GROUP;
+
+ if (syndrome_code != SYNDROME_MIN) {
+ char *dimm_str;
+ int pin;
+
+ get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+ &dimm_str, prop, first_dimm);
+ sprintf(buf, "%s, pin %3d", dimm_str, pin);
+ } else {
+ int dimm;
+
+ /* Multi-bit error, we just dump out all the
+ * dimm labels associated with this dimm group.
+ */
+ for (dimm = 0; dimm < JB_NUM_DIMMS_PER_GROUP; dimm++) {
+ sprintf(buf, "%s ",
+ prop->dimm_labels[first_dimm + dimm]);
+ buf += strlen(buf);
+ }
+ }
+
+ return 0;
+}
+
+static u64 __devinit jbusmc_dimm_group_size(u64 base,
+ const struct linux_prom64_registers *mem_regs,
+ int num_mem_regs)
+{
+ u64 max = base + (8UL * 1024 * 1024 * 1024);
+ u64 max_seen = base;
+ int i;
+
+ for (i = 0; i < num_mem_regs; i++) {
+ const struct linux_prom64_registers *ent;
+ u64 this_base;
+ u64 this_end;
+
+ ent = &mem_regs[i];
+ this_base = ent->phys_addr;
+ this_end = this_base + ent->reg_size;
+ if (base < this_base || base >= this_end)
+ continue;
+ if (this_end > max)
+ this_end = max;
+ if (this_end > max_seen)
+ max_seen = this_end;
+ }
+
+ return max_seen - base;
+}
+
+static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p,
+ unsigned long index,
+ const struct linux_prom64_registers *mem_regs,
+ int num_mem_regs)
+{
+ struct jbusmc_dimm_group *dp = &p->dimm_groups[index];
+
+ dp->controller = p;
+ dp->index = index;
+
+ dp->base_addr = (p->portid * (64UL * 1024 * 1024 * 1024));
+ dp->base_addr += (index * (8UL * 1024 * 1024 * 1024));
+ dp->size = jbusmc_dimm_group_size(dp->base_addr, mem_regs, num_mem_regs);
+}
+
+static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
+ const struct linux_prom64_registers *mem_regs,
+ int num_mem_regs)
+{
+ if (p->mc_reg_1 & JB_MC_REG1_DIMM1_BANK0) {
+ jbusmc_construct_one_dimm_group(p, 0, mem_regs, num_mem_regs);
+ p->num_dimm_groups++;
+ }
+ if (p->mc_reg_1 & JB_MC_REG1_DIMM2_BANK2) {
+ jbusmc_construct_one_dimm_group(p, 1, mem_regs, num_mem_regs);
+ p->num_dimm_groups++;
+ }
+}
+
+static int __devinit jbusmc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ const struct linux_prom64_registers *mem_regs;
+ struct device_node *mem_node;
+ int err, len, num_mem_regs;
+ struct jbusmc *p;
+ const u32 *prop;
+ const void *ml;
+
+ err = -ENODEV;
+ mem_node = of_find_node_by_path("/memory");
+ if (!mem_node) {
+ printk(KERN_ERR PFX "Cannot find /memory node.\n");
+ goto out;
+ }
+ mem_regs = of_get_property(mem_node, "reg", &len);
+ if (!mem_regs) {
+ printk(KERN_ERR PFX "Cannot get reg property of /memory node.\n");
+ goto out;
+ }
+ num_mem_regs = len / sizeof(*mem_regs);
+
+ err = -ENOMEM;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR PFX "Cannot allocate struct jbusmc.\n");
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&p->list);
+
+ err = -ENODEV;
+ prop = of_get_property(op->node, "portid", &len);
+ if (!prop || len != 4) {
+ printk(KERN_ERR PFX "Cannot find portid.\n");
+ goto out_free;
+ }
+
+ p->portid = *prop;
+
+ prop = of_get_property(op->node, "memory-control-register-1", &len);
+ if (!prop || len != 8) {
+ printk(KERN_ERR PFX "Cannot get memory control register 1.\n");
+ goto out_free;
+ }
+
+ p->mc_reg_1 = ((u64)prop[0] << 32) | (u64) prop[1];
+
+ err = -ENOMEM;
+ p->regs = of_ioremap(&op->resource[0], 0, JBUSMC_REGS_SIZE, "jbusmc");
+ if (!p->regs) {
+ printk(KERN_ERR PFX "Cannot map jbusmc regs.\n");
+ goto out_free;
+ }
+
+ err = -ENODEV;
+ ml = of_get_property(op->node, "memory-layout", &p->layout_len);
+ if (!ml) {
+ printk(KERN_ERR PFX "Cannot get memory layout property.\n");
+ goto out_iounmap;
+ }
+ if (p->layout_len > sizeof(p->layout)) {
+ printk(KERN_ERR PFX "Unexpected memory-layout size %d\n",
+ p->layout_len);
+ goto out_iounmap;
+ }
+ memcpy(&p->layout, ml, p->layout_len);
+
+ jbusmc_construct_dimm_groups(p, mem_regs, num_mem_regs);
+
+ mc_list_add(&p->list);
+
+ printk(KERN_INFO PFX "UltraSPARC-IIIi memory controller at %s\n",
+ op->node->full_name);
+
+ dev_set_drvdata(&op->dev, p);
+
+ err = 0;
+
+out:
+ return err;
+
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+
+out_free:
+ kfree(p);
+ goto out;
+}
+
/* Does BANK decode PHYS_ADDR? */
-static int bank_match(struct bank_info *bp, unsigned long phys_addr)
+static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
{
unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
@@ -118,25 +515,18 @@ static int bank_match(struct bank_info *bp, unsigned long phys_addr)
}
/* Given PHYS_ADDR, search memory controller banks for a match. */
-static struct bank_info *find_bank(unsigned long phys_addr)
+static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
{
- struct list_head *mctrl_head = &mctrl_list;
- struct list_head *mctrl_entry = mctrl_head->next;
+ struct chmc *p;
- for (;;) {
- struct mctrl_info *mp =
- list_entry(mctrl_entry, struct mctrl_info, list);
+ list_for_each_entry(p, &mctrl_list, list) {
int bank_no;
- if (mctrl_entry == mctrl_head)
- break;
- mctrl_entry = mctrl_entry->next;
-
for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
- struct bank_info *bp;
+ struct chmc_bank_info *bp;
- bp = &mp->logical_banks[bank_no];
- if (bank_match(bp, phys_addr))
+ bp = &p->logical_banks[bank_no];
+ if (chmc_bank_match(bp, phys_addr))
return bp;
}
}
@@ -145,17 +535,15 @@ static struct bank_info *find_bank(unsigned long phys_addr)
}
/* This is the main purpose of this driver. */
-#define SYNDROME_MIN -1
-#define SYNDROME_MAX 144
-int chmc_getunumber(int syndrome_code,
- unsigned long phys_addr,
- char *buf, int buflen)
+static int chmc_print_dimm(int syndrome_code,
+ unsigned long phys_addr,
+ char *buf, int buflen)
{
- struct bank_info *bp;
- struct obp_mem_layout *prop;
+ struct chmc_bank_info *bp;
+ struct chmc_obp_mem_layout *prop;
int bank_in_controller, first_dimm;
- bp = find_bank(phys_addr);
+ bp = chmc_find_bank(phys_addr);
if (bp == NULL ||
syndrome_code < SYNDROME_MIN ||
syndrome_code > SYNDROME_MAX) {
@@ -166,60 +554,18 @@ int chmc_getunumber(int syndrome_code,
return 0;
}
- prop = &bp->mp->layout_prop;
+ prop = &bp->p->layout_prop;
bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
first_dimm = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
first_dimm *= CHMCTRL_NDIMMS;
if (syndrome_code != SYNDROME_MIN) {
- struct obp_map *map;
- int qword, where_in_line, where, map_index, map_offset;
- unsigned int map_val;
+ char *dimm_str;
+ int pin;
- /* Yaay, single bit error so we can figure out
- * the exact dimm.
- */
- if (prop->symmetric)
- map = &prop->map[0];
- else
- map = &prop->map[1];
-
- /* Covert syndrome code into the way the bits are
- * positioned on the bus.
- */
- if (syndrome_code < 144 - 16)
- syndrome_code += 16;
- else if (syndrome_code < 144)
- syndrome_code -= (144 - 7);
- else if (syndrome_code < (144 + 3))
- syndrome_code -= (144 + 3 - 4);
- else
- syndrome_code -= 144 + 3;
-
- /* All this magic has to do with how a cache line
- * comes over the wire on Safari. A 64-bit line
- * comes over in 4 quadword cycles, each of which
- * transmit ECC/MTAG info as well as the actual
- * data. 144 bits per quadword, 576 total.
- */
-#define LINE_SIZE 64
-#define LINE_ADDR_MSK (LINE_SIZE - 1)
-#define QW_PER_LINE 4
-#define QW_BYTES (LINE_SIZE / QW_PER_LINE)
-#define QW_BITS 144
-#define LAST_BIT (576 - 1)
-
- qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES;
- where_in_line = ((3 - qword) * QW_BITS) + syndrome_code;
- where = (LAST_BIT - where_in_line);
- map_index = where >> 2;
- map_offset = where & 0x3;
- map_val = map->dimm_map[map_index];
- map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1));
-
- sprintf(buf, "%s, pin %3d",
- prop->dimm_labels[first_dimm + map_val],
- map->pin_map[where_in_line]);
+ get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+ &dimm_str, prop, first_dimm);
+ sprintf(buf, "%s, pin %3d", dimm_str, pin);
} else {
int dimm;
@@ -240,7 +586,7 @@ int chmc_getunumber(int syndrome_code,
* the code is executing, you must use special ASI load/store else
* you go through the global mapping.
*/
-static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
+static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset)
{
unsigned long ret, this_cpu;
@@ -248,14 +594,14 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
this_cpu = real_hard_smp_processor_id();
- if (mp->portid == this_cpu) {
+ if (p->portid == this_cpu) {
__asm__ __volatile__("ldxa [%1] %2, %0"
: "=r" (ret)
: "r" (offset), "i" (ASI_MCU_CTRL_REG));
} else {
__asm__ __volatile__("ldxa [%1] %2, %0"
: "=r" (ret)
- : "r" (mp->regs + offset),
+ : "r" (p->regs + offset),
"i" (ASI_PHYS_BYPASS_EC_E));
}
@@ -265,178 +611,253 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
}
#if 0 /* currently unused */
-static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val)
+static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val)
{
- if (mp->portid == smp_processor_id()) {
+ if (p->portid == smp_processor_id()) {
__asm__ __volatile__("stxa %0, [%1] %2"
: : "r" (val),
"r" (offset), "i" (ASI_MCU_CTRL_REG));
} else {
__asm__ __volatile__("ldxa %0, [%1] %2"
: : "r" (val),
- "r" (mp->regs + offset),
+ "r" (p->regs + offset),
"i" (ASI_PHYS_BYPASS_EC_E));
}
}
#endif
-static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val)
+static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val)
{
- struct bank_info *p = &mp->logical_banks[which_bank];
-
- p->mp = mp;
- p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank;
- p->raw_reg = val;
- p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
- p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
- p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
- p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
- p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
-
- p->base = (p->um);
- p->base &= ~(p->uk);
- p->base <<= PA_UPPER_BITS_SHIFT;
-
- switch(p->lk) {
+ struct chmc_bank_info *bp = &p->logical_banks[which_bank];
+
+ bp->p = p;
+ bp->bank_id = (CHMCTRL_NBANKS * p->portid) + which_bank;
+ bp->raw_reg = val;
+ bp->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
+ bp->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
+ bp->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
+ bp->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
+ bp->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
+
+ bp->base = (bp->um);
+ bp->base &= ~(bp->uk);
+ bp->base <<= PA_UPPER_BITS_SHIFT;
+
+ switch(bp->lk) {
case 0xf:
default:
- p->interleave = 1;
+ bp->interleave = 1;
break;
case 0xe:
- p->interleave = 2;
+ bp->interleave = 2;
break;
case 0xc:
- p->interleave = 4;
+ bp->interleave = 4;
break;
case 0x8:
- p->interleave = 8;
+ bp->interleave = 8;
break;
case 0x0:
- p->interleave = 16;
+ bp->interleave = 16;
break;
};
/* UK[10] is reserved, and UK[11] is not set for the SDRAM
* bank size definition.
*/
- p->size = (((unsigned long)p->uk &
- ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
- p->size /= p->interleave;
+ bp->size = (((unsigned long)bp->uk &
+ ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
+ bp->size /= bp->interleave;
}
-static void fetch_decode_regs(struct mctrl_info *mp)
+static void chmc_fetch_decode_regs(struct chmc *p)
{
- if (mp->layout_size == 0)
+ if (p->layout_size == 0)
return;
- interpret_one_decode_reg(mp, 0,
- read_mcreg(mp, CHMCTRL_DECODE1));
- interpret_one_decode_reg(mp, 1,
- read_mcreg(mp, CHMCTRL_DECODE2));
- interpret_one_decode_reg(mp, 2,
- read_mcreg(mp, CHMCTRL_DECODE3));
- interpret_one_decode_reg(mp, 3,
- read_mcreg(mp, CHMCTRL_DECODE4));
+ chmc_interpret_one_decode_reg(p, 0,
+ chmc_read_mcreg(p, CHMCTRL_DECODE1));
+ chmc_interpret_one_decode_reg(p, 1,
+ chmc_read_mcreg(p, CHMCTRL_DECODE2));
+ chmc_interpret_one_decode_reg(p, 2,
+ chmc_read_mcreg(p, CHMCTRL_DECODE3));
+ chmc_interpret_one_decode_reg(p, 3,
+ chmc_read_mcreg(p, CHMCTRL_DECODE4));
}
-static int init_one_mctrl(struct device_node *dp)
+static int __devinit chmc_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
- int portid = of_getintprop_default(dp, "portid", -1);
- const struct linux_prom64_registers *regs;
+ struct device_node *dp = op->node;
+ unsigned long ver;
const void *pval;
- int len;
+ int len, portid;
+ struct chmc *p;
+ int err;
+
+ err = -ENODEV;
+ __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID)
+ goto out;
- if (!mp)
- return -1;
+ portid = of_getintprop_default(dp, "portid", -1);
if (portid == -1)
- goto fail;
+ goto out;
- mp->portid = portid;
pval = of_get_property(dp, "memory-layout", &len);
- mp->layout_size = len;
- if (!pval)
- mp->layout_size = 0;
- else {
- if (mp->layout_size > sizeof(mp->layout_prop))
- goto fail;
- memcpy(&mp->layout_prop, pval, len);
+ if (pval && len > sizeof(p->layout_prop)) {
+ printk(KERN_ERR PFX "Unexpected memory-layout property "
+ "size %d.\n", len);
+ goto out;
}
- regs = of_get_property(dp, "reg", NULL);
- if (!regs || regs->reg_size != 0x48)
- goto fail;
+ err = -ENOMEM;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR PFX "Could not allocate struct chmc.\n");
+ goto out;
+ }
- mp->regs = ioremap(regs->phys_addr, regs->reg_size);
- if (mp->regs == NULL)
- goto fail;
+ p->portid = portid;
+ p->layout_size = len;
+ if (!pval)
+ p->layout_size = 0;
+ else
+ memcpy(&p->layout_prop, pval, len);
+
+ p->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc");
+ if (!p->regs) {
+ printk(KERN_ERR PFX "Could not map registers.\n");
+ goto out_free;
+ }
- if (mp->layout_size != 0UL) {
- mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1);
- mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2);
- mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3);
- mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4);
- mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL);
+ if (p->layout_size != 0UL) {
+ p->timing_control1 = chmc_read_mcreg(p, CHMCTRL_TCTRL1);
+ p->timing_control2 = chmc_read_mcreg(p, CHMCTRL_TCTRL2);
+ p->timing_control3 = chmc_read_mcreg(p, CHMCTRL_TCTRL3);
+ p->timing_control4 = chmc_read_mcreg(p, CHMCTRL_TCTRL4);
+ p->memaddr_control = chmc_read_mcreg(p, CHMCTRL_MACTRL);
}
- fetch_decode_regs(mp);
+ chmc_fetch_decode_regs(p);
- list_add(&mp->list, &mctrl_list);
+ mc_list_add(&p->list);
- /* Report the device. */
- printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
+ printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n",
dp->full_name,
- mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
+ (p->layout_size ? "ACTIVE" : "INACTIVE"));
- return 0;
+ dev_set_drvdata(&op->dev, p);
+
+ err = 0;
+
+out:
+ return err;
+
+out_free:
+ kfree(p);
+ goto out;
+}
-fail:
- if (mp) {
- if (mp->regs != NULL)
- iounmap(mp->regs);
- kfree(mp);
+static int __devinit us3mc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ if (mc_type == MC_TYPE_SAFARI)
+ return chmc_probe(op, match);
+ else if (mc_type == MC_TYPE_JBUS)
+ return jbusmc_probe(op, match);
+ return -ENODEV;
+}
+
+static void __devexit chmc_destroy(struct of_device *op, struct chmc *p)
+{
+ list_del(&p->list);
+ of_iounmap(&op->resource[0], p->regs, 0x48);
+ kfree(p);
+}
+
+static void __devexit jbusmc_destroy(struct of_device *op, struct jbusmc *p)
+{
+ mc_list_del(&p->list);
+ of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+ kfree(p);
+}
+
+static int __devexit us3mc_remove(struct of_device *op)
+{
+ void *p = dev_get_drvdata(&op->dev);
+
+ if (p) {
+ if (mc_type == MC_TYPE_SAFARI)
+ chmc_destroy(op, p);
+ else if (mc_type == MC_TYPE_JBUS)
+ jbusmc_destroy(op, p);
}
- return -1;
+ return 0;
+}
+
+static const struct of_device_id us3mc_match[] = {
+ {
+ .name = "memory-controller",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, us3mc_match);
+
+static struct of_platform_driver us3mc_driver = {
+ .name = "us3mc",
+ .match_table = us3mc_match,
+ .probe = us3mc_probe,
+ .remove = __devexit_p(us3mc_remove),
+};
+
+static inline bool us3mc_platform(void)
+{
+ if (tlb_type == cheetah || tlb_type == cheetah_plus)
+ return true;
+ return false;
}
-static int __init chmc_init(void)
+static int __init us3mc_init(void)
{
- struct device_node *dp;
+ unsigned long ver;
+ int ret;
- /* This driver is only for cheetah platforms. */
- if (tlb_type != cheetah && tlb_type != cheetah_plus)
+ if (!us3mc_platform())
return -ENODEV;
- for_each_node_by_name(dp, "memory-controller")
- init_one_mctrl(dp);
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID) {
+ mc_type = MC_TYPE_JBUS;
+ us3mc_dimm_printer = jbusmc_print_dimm;
+ } else {
+ mc_type = MC_TYPE_SAFARI;
+ us3mc_dimm_printer = chmc_print_dimm;
+ }
- for_each_node_by_name(dp, "mc-us3")
- init_one_mctrl(dp);
+ ret = register_dimm_printer(us3mc_dimm_printer);
- return 0;
+ if (!ret) {
+ ret = of_register_driver(&us3mc_driver, &of_bus_type);
+ if (ret)
+ unregister_dimm_printer(us3mc_dimm_printer);
+ }
+ return ret;
}
-static void __exit chmc_cleanup(void)
+static void __exit us3mc_cleanup(void)
{
- struct list_head *head = &mctrl_list;
- struct list_head *tmp = head->next;
-
- for (;;) {
- struct mctrl_info *p =
- list_entry(tmp, struct mctrl_info, list);
- if (tmp == head)
- break;
- tmp = tmp->next;
-
- list_del(&p->list);
- iounmap(p->regs);
- kfree(p);
+ if (us3mc_platform()) {
+ unregister_dimm_printer(us3mc_dimm_printer);
+ of_unregister_driver(&us3mc_driver);
}
}
-module_init(chmc_init);
-module_exit(chmc_cleanup);
+module_init(us3mc_init);
+module_exit(us3mc_cleanup);
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 0097c08dc60..0c9ac83ed0a 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -1,7 +1,7 @@
/* cpu.c: Dinky routines to look for the kind of Sparc cpu
* we are on.
*
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -19,53 +19,86 @@
DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
-struct cpu_iu_info {
- short manuf;
- short impl;
- char* cpu_name; /* should be enough I hope... */
+struct cpu_chip_info {
+ unsigned short manuf;
+ unsigned short impl;
+ const char *cpu_name;
+ const char *fp_name;
};
-struct cpu_fp_info {
- short manuf;
- short impl;
- char fpu_vers;
- char* fp_name;
+static const struct cpu_chip_info cpu_chips[] = {
+ {
+ .manuf = 0x17,
+ .impl = 0x10,
+ .cpu_name = "TI UltraSparc I (SpitFire)",
+ .fp_name = "UltraSparc I integrated FPU",
+ },
+ {
+ .manuf = 0x22,
+ .impl = 0x10,
+ .cpu_name = "TI UltraSparc I (SpitFire)",
+ .fp_name = "UltraSparc I integrated FPU",
+ },
+ {
+ .manuf = 0x17,
+ .impl = 0x11,
+ .cpu_name = "TI UltraSparc II (BlackBird)",
+ .fp_name = "UltraSparc II integrated FPU",
+ },
+ {
+ .manuf = 0x17,
+ .impl = 0x12,
+ .cpu_name = "TI UltraSparc IIi (Sabre)",
+ .fp_name = "UltraSparc IIi integrated FPU",
+ },
+ {
+ .manuf = 0x17,
+ .impl = 0x13,
+ .cpu_name = "TI UltraSparc IIe (Hummingbird)",
+ .fp_name = "UltraSparc IIe integrated FPU",
+ },
+ {
+ .manuf = 0x3e,
+ .impl = 0x14,
+ .cpu_name = "TI UltraSparc III (Cheetah)",
+ .fp_name = "UltraSparc III integrated FPU",
+ },
+ {
+ .manuf = 0x3e,
+ .impl = 0x15,
+ .cpu_name = "TI UltraSparc III+ (Cheetah+)",
+ .fp_name = "UltraSparc III+ integrated FPU",
+ },
+ {
+ .manuf = 0x3e,
+ .impl = 0x16,
+ .cpu_name = "TI UltraSparc IIIi (Jalapeno)",
+ .fp_name = "UltraSparc IIIi integrated FPU",
+ },
+ {
+ .manuf = 0x3e,
+ .impl = 0x18,
+ .cpu_name = "TI UltraSparc IV (Jaguar)",
+ .fp_name = "UltraSparc IV integrated FPU",
+ },
+ {
+ .manuf = 0x3e,
+ .impl = 0x19,
+ .cpu_name = "TI UltraSparc IV+ (Panther)",
+ .fp_name = "UltraSparc IV+ integrated FPU",
+ },
+ {
+ .manuf = 0x3e,
+ .impl = 0x22,
+ .cpu_name = "TI UltraSparc IIIi+ (Serrano)",
+ .fp_name = "UltraSparc IIIi+ integrated FPU",
+ },
};
-static struct cpu_fp_info linux_sparc_fpu[] = {
- { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
- { 0x22, 0x10, 0, "UltraSparc I integrated FPU"},
- { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
- { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
- { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
- { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
- { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
- { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"},
- { 0x3e, 0x18, 0, "UltraSparc IV integrated FPU"},
- { 0x3e, 0x19, 0, "UltraSparc IV+ integrated FPU"},
- { 0x3e, 0x22, 0, "UltraSparc IIIi+ integrated FPU"},
-};
-
-#define NSPARCFPU ARRAY_SIZE(linux_sparc_fpu)
-
-static struct cpu_iu_info linux_sparc_chips[] = {
- { 0x17, 0x10, "TI UltraSparc I (SpitFire)"},
- { 0x22, 0x10, "TI UltraSparc I (SpitFire)"},
- { 0x17, 0x11, "TI UltraSparc II (BlackBird)"},
- { 0x17, 0x12, "TI UltraSparc IIi (Sabre)"},
- { 0x17, 0x13, "TI UltraSparc IIe (Hummingbird)"},
- { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
- { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
- { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"},
- { 0x3e, 0x18, "TI UltraSparc IV (Jaguar)"},
- { 0x3e, 0x19, "TI UltraSparc IV+ (Panther)"},
- { 0x3e, 0x22, "TI UltraSparc IIIi+ (Serrano)"},
-};
+#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
-#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
-
-char *sparc_cpu_type;
-char *sparc_fpu_type;
+const char *sparc_cpu_type;
+const char *sparc_fpu_type;
static void __init sun4v_cpu_probe(void)
{
@@ -89,68 +122,45 @@ static void __init sun4v_cpu_probe(void)
}
}
-void __init cpu_probe(void)
+static const struct cpu_chip_info * __init find_cpu_chip(unsigned short manuf,
+ unsigned short impl)
{
- unsigned long ver, fpu_vers, manuf, impl, fprs;
int i;
-
- if (tlb_type == hypervisor) {
- sun4v_cpu_probe();
- return;
- }
- fprs = fprs_read();
- fprs_write(FPRS_FEF);
- __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
- : "=&r" (ver)
- : "r" (&fpu_vers));
- fprs_write(fprs);
-
- manuf = ((ver >> 48) & 0xffff);
- impl = ((ver >> 32) & 0xffff);
-
- fpu_vers = ((fpu_vers >> 17) & 0x7);
-
-retry:
- for (i = 0; i < NSPARCCHIPS; i++) {
- if (linux_sparc_chips[i].manuf == manuf) {
- if (linux_sparc_chips[i].impl == impl) {
- sparc_cpu_type =
- linux_sparc_chips[i].cpu_name;
- break;
- }
- }
- }
+ for (i = 0; i < ARRAY_SIZE(cpu_chips); i++) {
+ const struct cpu_chip_info *p = &cpu_chips[i];
- if (i == NSPARCCHIPS) {
- /* Maybe it is a cheetah+ derivative, report it as cheetah+
- * in that case until we learn the real names.
- */
- if (manuf == 0x3e &&
- impl > 0x15) {
- impl = 0x15;
- goto retry;
- } else {
- printk("DEBUG: manuf[%lx] impl[%lx]\n",
- manuf, impl);
- }
- sparc_cpu_type = "Unknown CPU";
+ if (p->manuf == manuf && p->impl == impl)
+ return p;
}
+ return NULL;
+}
- for (i = 0; i < NSPARCFPU; i++) {
- if (linux_sparc_fpu[i].manuf == manuf &&
- linux_sparc_fpu[i].impl == impl) {
- if (linux_sparc_fpu[i].fpu_vers == fpu_vers) {
- sparc_fpu_type =
- linux_sparc_fpu[i].fp_name;
- break;
- }
+static int __init cpu_type_probe(void)
+{
+ if (tlb_type == hypervisor) {
+ sun4v_cpu_probe();
+ } else {
+ unsigned long ver, manuf, impl;
+ const struct cpu_chip_info *p;
+
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+
+ manuf = ((ver >> 48) & 0xffff);
+ impl = ((ver >> 32) & 0xffff);
+
+ p = find_cpu_chip(manuf, impl);
+ if (p) {
+ sparc_cpu_type = p->cpu_name;
+ sparc_fpu_type = p->fp_name;
+ } else {
+ printk(KERN_ERR "CPU: Unknown chip, manuf[%lx] impl[%lx]\n",
+ manuf, impl);
+ sparc_cpu_type = "Unknown CPU";
+ sparc_fpu_type = "Unknown FPU";
}
}
-
- if (i == NSPARCFPU) {
- printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n",
- manuf, impl, fpu_vers);
- sparc_fpu_type = "Unknown FPU";
- }
+ return 0;
}
+
+arch_initcall(cpu_type_probe);
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index d0fa5aa3893..f52e0534d91 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -1,6 +1,6 @@
/* ds.c: Domain Services driver for Logical Domains
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
@@ -1217,7 +1217,7 @@ static int ds_remove(struct vio_dev *vdev)
return 0;
}
-static struct vio_device_id ds_match[] = {
+static struct vio_device_id __initdata ds_match[] = {
{
.type = "domain-services-port",
},
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 60d36d14255..77dbf6d45fa 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,5 +1,4 @@
-/*
- * ebus.c: PCI to EBus bridge device.
+/* ebus.c: EBUS DMA library code.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -9,23 +8,11 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-/* EBUS dma library. */
+#include <asm/ebus_dma.h>
+#include <asm/io.h>
#define EBDMA_CSR 0x00UL /* Control/Status */
#define EBDMA_ADDR 0x04UL /* DMA Address */
@@ -268,283 +255,3 @@ void ebus_dma_enable(struct ebus_dma_info *p, int on)
spin_unlock_irqrestore(&p->lock, flags);
}
EXPORT_SYMBOL(ebus_dma_enable);
-
-struct linux_ebus *ebus_chain = NULL;
-
-static inline void *ebus_alloc(size_t size)
-{
- void *mem;
-
- mem = kzalloc(size, GFP_ATOMIC);
- if (!mem)
- panic("ebus_alloc: out of memory");
- return mem;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
- struct linux_ebus_child *dev,
- int non_standard_regs)
-{
- struct of_device *op;
- const int *regs;
- int i, len;
-
- dev->prom_node = dp;
- printk(" (%s)", dp->name);
-
- regs = of_get_property(dp, "reg", &len);
- if (!regs)
- dev->num_addrs = 0;
- else
- dev->num_addrs = len / sizeof(regs[0]);
-
- if (non_standard_regs) {
- /* This is to handle reg properties which are not
- * in the parent relative format. One example are
- * children of the i2c device on CompactPCI systems.
- *
- * So, for such devices we just record the property
- * raw in the child resources.
- */
- for (i = 0; i < dev->num_addrs; i++)
- dev->resource[i].start = regs[i];
- } else {
- for (i = 0; i < dev->num_addrs; i++) {
- int rnum = regs[i];
- if (rnum >= dev->parent->num_addrs) {
- prom_printf("UGH: property for %s was %d, need < %d\n",
- dp->name, len, dev->parent->num_addrs);
- prom_halt();
- }
- dev->resource[i].start = dev->parent->resource[i].start;
- dev->resource[i].end = dev->parent->resource[i].end;
- dev->resource[i].flags = IORESOURCE_MEM;
- dev->resource[i].name = dp->name;
- }
- }
-
- op = of_find_device_by_node(dp);
- if (!op) {
- dev->num_irqs = 0;
- } else {
- dev->num_irqs = op->num_irqs;
- for (i = 0; i < dev->num_irqs; i++)
- dev->irqs[i] = op->irqs[i];
- }
-
- if (!dev->num_irqs) {
- /*
- * Oh, well, some PROMs don't export interrupts
- * property to children of EBus devices...
- *
- * Be smart about PS/2 keyboard and mouse.
- */
- if (!strcmp(dev->parent->prom_node->name, "8042")) {
- if (!strcmp(dev->prom_node->name, "kb_ps2")) {
- dev->num_irqs = 1;
- dev->irqs[0] = dev->parent->irqs[0];
- } else {
- dev->num_irqs = 1;
- dev->irqs[0] = dev->parent->irqs[1];
- }
- }
- }
-}
-
-static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
-{
- if (!strcmp(dev->prom_node->name, "i2c") ||
- !strcmp(dev->prom_node->name, "SUNW,lombus"))
- return 1;
- return 0;
-}
-
-static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
-{
- struct linux_ebus_child *child;
- struct dev_archdata *sd;
- struct of_device *op;
- int i, len;
-
- dev->prom_node = dp;
-
- printk(" [%s", dp->name);
-
- op = of_find_device_by_node(dp);
- if (!op) {
- dev->num_addrs = 0;
- dev->num_irqs = 0;
- } else {
- const int *regs = of_get_property(dp, "reg", &len);
-
- if (!regs)
- len = 0;
- dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
- for (i = 0; i < dev->num_addrs; i++)
- memcpy(&dev->resource[i],
- &op->resource[i],
- sizeof(struct resource));
-
- dev->num_irqs = op->num_irqs;
- for (i = 0; i < dev->num_irqs; i++)
- dev->irqs[i] = op->irqs[i];
- }
-
- sd = &dev->ofdev.dev.archdata;
- sd->prom_node = dp;
- sd->op = &dev->ofdev;
- sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
- sd->stc = dev->bus->ofdev.dev.parent->archdata.stc;
- sd->numa_node = dev->bus->ofdev.dev.parent->archdata.numa_node;
-
- dev->ofdev.node = dp;
- dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
- dev->ofdev.dev.bus = &ebus_bus_type;
- dev_set_name(&dev->ofdev.dev, "ebus[%08x]", dp->node);
-
- /* Register with core */
- if (of_device_register(&dev->ofdev) != 0)
- printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- dp->path_component_name);
-
- dp = dp->child;
- if (dp) {
- printk(" ->");
- dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
-
- child = dev->children;
- child->next = NULL;
- child->parent = dev;
- child->bus = dev->bus;
- fill_ebus_child(dp, child,
- child_regs_nonstandard(dev));
-
- while ((dp = dp->sibling) != NULL) {
- child->next = ebus_alloc(sizeof(struct linux_ebus_child));
-
- child = child->next;
- child->next = NULL;
- child->parent = dev;
- child->bus = dev->bus;
- fill_ebus_child(dp, child,
- child_regs_nonstandard(dev));
- }
- }
- printk("]");
-}
-
-static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
-{
- struct pci_dev *pdev = start;
-
- while ((pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev)))
- if (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
- pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)
- break;
-
- *is_rio_p = !!(pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS));
-
- return pdev;
-}
-
-void __init ebus_init(void)
-{
- struct linux_ebus_device *dev;
- struct linux_ebus *ebus;
- struct pci_dev *pdev;
- struct device_node *dp;
- int is_rio;
- int num_ebus = 0;
-
- pdev = find_next_ebus(NULL, &is_rio);
- if (!pdev) {
- printk("ebus: No EBus's found.\n");
- return;
- }
-
- dp = pci_device_to_OF_node(pdev);
-
- ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
- ebus->next = NULL;
- ebus->is_rio = is_rio;
-
- while (dp) {
- struct device_node *child;
-
- /* SUNW,pci-qfe uses four empty ebuses on it.
- I think we should not consider them here,
- as they have half of the properties this
- code expects and once we do PCI hot-plug,
- we'd have to tweak with the ebus_chain
- in the runtime after initialization. -jj */
- if (!dp->child) {
- pdev = find_next_ebus(pdev, &is_rio);
- if (!pdev) {
- if (ebus == ebus_chain) {
- ebus_chain = NULL;
- printk("ebus: No EBus's found.\n");
- return;
- }
- break;
- }
- ebus->is_rio = is_rio;
- dp = pci_device_to_OF_node(pdev);
- continue;
- }
- printk("ebus%d:", num_ebus);
-
- ebus->index = num_ebus;
- ebus->prom_node = dp;
- ebus->self = pdev;
-
- ebus->ofdev.node = dp;
- ebus->ofdev.dev.parent = &pdev->dev;
- ebus->ofdev.dev.bus = &ebus_bus_type;
- dev_set_name(&ebus->ofdev.dev, "ebus%d", num_ebus);
-
- /* Register with core */
- if (of_device_register(&ebus->ofdev) != 0)
- printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- dp->path_component_name);
-
-
- child = dp->child;
- if (!child)
- goto next_ebus;
-
- ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
-
- dev = ebus->devices;
- dev->next = NULL;
- dev->children = NULL;
- dev->bus = ebus;
- fill_ebus_device(child, dev);
-
- while ((child = child->sibling) != NULL) {
- dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
-
- dev = dev->next;
- dev->next = NULL;
- dev->children = NULL;
- dev->bus = ebus;
- fill_ebus_device(child, dev);
- }
-
- next_ebus:
- printk("\n");
-
- pdev = find_next_ebus(pdev, &is_rio);
- if (!pdev)
- break;
-
- dp = pci_device_to_OF_node(pdev);
-
- ebus->next = ebus_alloc(sizeof(struct linux_ebus));
- ebus = ebus->next;
- ebus->next = NULL;
- ebus->is_rio = is_rio;
- ++num_ebus;
- }
- pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
-}
diff --git a/arch/sparc64/kernel/entry.h b/arch/sparc64/kernel/entry.h
index fc294a29289..34d7ab5e10d 100644
--- a/arch/sparc64/kernel/entry.h
+++ b/arch/sparc64/kernel/entry.h
@@ -5,8 +5,8 @@
#include <linux/types.h>
#include <linux/init.h>
-extern char *sparc_cpu_type;
-extern char *sparc_fpu_type;
+extern const char *sparc_cpu_type;
+extern const char *sparc_fpu_type;
extern void __init per_cpu_patch(void);
extern void __init sun4v_patch(void);
@@ -22,7 +22,8 @@ extern void do_notify_resume(struct pt_regs *regs,
unsigned long orig_i0,
unsigned long thread_info_flags);
-extern asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p);
+extern asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
extern void bad_trap_tl1(struct pt_regs *regs, long lvl);
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c9afef093d5..353226fa023 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/threads.h>
#include <linux/init.h>
+#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/asi.h>
#include <asm/pstate.h>
diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c
index 691760b5b01..1d272c3b574 100644
--- a/arch/sparc64/kernel/hvapi.c
+++ b/arch/sparc64/kernel/hvapi.c
@@ -9,7 +9,6 @@
#include <asm/hypervisor.h>
#include <asm/oplib.h>
-#include <asm/sstate.h>
/* If the hypervisor indicates that the API setting
* calls are unsupported, by returning HV_EBADTRAP or
@@ -184,8 +183,6 @@ void __init sun4v_hvapi_init(void)
if (sun4v_hvapi_register(group, major, &minor))
goto bad;
- sun4v_sstate_init();
-
return;
bad:
diff --git a/arch/sparc64/kernel/hvcalls.S b/arch/sparc64/kernel/hvcalls.S
index a2810f3ac70..e066269d159 100644
--- a/arch/sparc64/kernel/hvcalls.S
+++ b/arch/sparc64/kernel/hvcalls.S
@@ -3,89 +3,75 @@
*
* returns %o0: sysino
*/
- .globl sun4v_devino_to_sysino
- .type sun4v_devino_to_sysino,#function
-sun4v_devino_to_sysino:
+ENTRY(sun4v_devino_to_sysino)
mov HV_FAST_INTR_DEVINO2SYSINO, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
+ENDPROC(sun4v_devino_to_sysino)
/* %o0: sysino
*
* returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
- .globl sun4v_intr_getenabled
- .type sun4v_intr_getenabled,#function
-sun4v_intr_getenabled:
+ENTRY(sun4v_intr_getenabled)
mov HV_FAST_INTR_GETENABLED, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_intr_getenabled, .-sun4v_intr_getenabled
+ENDPROC(sun4v_intr_getenabled)
/* %o0: sysino
* %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
- .globl sun4v_intr_setenabled
- .type sun4v_intr_setenabled,#function
-sun4v_intr_setenabled:
+ENTRY(sun4v_intr_setenabled)
mov HV_FAST_INTR_SETENABLED, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_intr_setenabled, .-sun4v_intr_setenabled
+ENDPROC(sun4v_intr_setenabled)
/* %o0: sysino
*
* returns %o0: intr_state (HV_INTR_STATE_*)
*/
- .globl sun4v_intr_getstate
- .type sun4v_intr_getstate,#function
-sun4v_intr_getstate:
+ENTRY(sun4v_intr_getstate)
mov HV_FAST_INTR_GETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_intr_getstate, .-sun4v_intr_getstate
+ENDPROC(sun4v_intr_getstate)
/* %o0: sysino
* %o1: intr_state (HV_INTR_STATE_*)
*/
- .globl sun4v_intr_setstate
- .type sun4v_intr_setstate,#function
-sun4v_intr_setstate:
+ENTRY(sun4v_intr_setstate)
mov HV_FAST_INTR_SETSTATE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_intr_setstate, .-sun4v_intr_setstate
+ENDPROC(sun4v_intr_setstate)
/* %o0: sysino
*
* returns %o0: cpuid
*/
- .globl sun4v_intr_gettarget
- .type sun4v_intr_gettarget,#function
-sun4v_intr_gettarget:
+ENTRY(sun4v_intr_gettarget)
mov HV_FAST_INTR_GETTARGET, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
- .size sun4v_intr_gettarget, .-sun4v_intr_gettarget
+ENDPROC(sun4v_intr_gettarget)
/* %o0: sysino
* %o1: cpuid
*/
- .globl sun4v_intr_settarget
- .type sun4v_intr_settarget,#function
-sun4v_intr_settarget:
+ENTRY(sun4v_intr_settarget)
mov HV_FAST_INTR_SETTARGET, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_intr_settarget, .-sun4v_intr_settarget
+ENDPROC(sun4v_intr_settarget)
/* %o0: cpuid
* %o1: pc
@@ -94,37 +80,31 @@ sun4v_intr_settarget:
*
* returns %o0: status
*/
- .globl sun4v_cpu_start
- .type sun4v_cpu_start,#function
-sun4v_cpu_start:
+ENTRY(sun4v_cpu_start)
mov HV_FAST_CPU_START, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_start, .-sun4v_cpu_start
+ENDPROC(sun4v_cpu_start)
/* %o0: cpuid
*
* returns %o0: status
*/
- .globl sun4v_cpu_stop
- .type sun4v_cpu_stop,#function
-sun4v_cpu_stop:
+ENTRY(sun4v_cpu_stop)
mov HV_FAST_CPU_STOP, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_stop, .-sun4v_cpu_stop
+ENDPROC(sun4v_cpu_stop)
/* returns %o0: status */
- .globl sun4v_cpu_yield
- .type sun4v_cpu_yield, #function
-sun4v_cpu_yield:
+ENTRY(sun4v_cpu_yield)
mov HV_FAST_CPU_YIELD, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_yield, .-sun4v_cpu_yield
+ENDPROC(sun4v_cpu_yield)
/* %o0: type
* %o1: queue paddr
@@ -132,14 +112,12 @@ sun4v_cpu_yield:
*
* returns %o0: status
*/
- .globl sun4v_cpu_qconf
- .type sun4v_cpu_qconf,#function
-sun4v_cpu_qconf:
+ENTRY(sun4v_cpu_qconf)
mov HV_FAST_CPU_QCONF, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_qconf, .-sun4v_cpu_qconf
+ENDPROC(sun4v_cpu_qconf)
/* %o0: num cpus in cpu list
* %o1: cpu list paddr
@@ -147,23 +125,19 @@ sun4v_cpu_qconf:
*
* returns %o0: status
*/
- .globl sun4v_cpu_mondo_send
- .type sun4v_cpu_mondo_send,#function
-sun4v_cpu_mondo_send:
+ENTRY(sun4v_cpu_mondo_send)
mov HV_FAST_CPU_MONDO_SEND, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
+ENDPROC(sun4v_cpu_mondo_send)
/* %o0: CPU ID
*
* returns %o0: -status if status non-zero, else
* %o0: cpu state as HV_CPU_STATE_*
*/
- .globl sun4v_cpu_state
- .type sun4v_cpu_state,#function
-sun4v_cpu_state:
+ENTRY(sun4v_cpu_state)
mov HV_FAST_CPU_STATE, %o5
ta HV_FAST_TRAP
brnz,pn %o0, 1f
@@ -171,7 +145,7 @@ sun4v_cpu_state:
mov %o1, %o0
1: retl
nop
- .size sun4v_cpu_state, .-sun4v_cpu_state
+ENDPROC(sun4v_cpu_state)
/* %o0: virtual address
* %o1: must be zero
@@ -180,28 +154,24 @@ sun4v_cpu_state:
*
* returns %o0: status
*/
- .globl sun4v_mmu_map_perm_addr
- .type sun4v_mmu_map_perm_addr,#function
-sun4v_mmu_map_perm_addr:
+ENTRY(sun4v_mmu_map_perm_addr)
mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
+ENDPROC(sun4v_mmu_map_perm_addr)
/* %o0: number of TSB descriptions
* %o1: TSB descriptions real address
*
* returns %o0: status
*/
- .globl sun4v_mmu_tsb_ctx0
- .type sun4v_mmu_tsb_ctx0,#function
-sun4v_mmu_tsb_ctx0:
+ENTRY(sun4v_mmu_tsb_ctx0)
mov HV_FAST_MMU_TSB_CTX0, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
+ENDPROC(sun4v_mmu_tsb_ctx0)
/* %o0: API group number
* %o1: pointer to unsigned long major number storage
@@ -209,9 +179,7 @@ sun4v_mmu_tsb_ctx0:
*
* returns %o0: status
*/
- .globl sun4v_get_version
- .type sun4v_get_version,#function
-sun4v_get_version:
+ENTRY(sun4v_get_version)
mov HV_CORE_GET_VER, %o5
mov %o1, %o3
mov %o2, %o4
@@ -219,7 +187,7 @@ sun4v_get_version:
stx %o1, [%o3]
retl
stx %o2, [%o4]
- .size sun4v_get_version, .-sun4v_get_version
+ENDPROC(sun4v_get_version)
/* %o0: API group number
* %o1: desired major number
@@ -228,51 +196,43 @@ sun4v_get_version:
*
* returns %o0: status
*/
- .globl sun4v_set_version
- .type sun4v_set_version,#function
-sun4v_set_version:
+ENTRY(sun4v_set_version)
mov HV_CORE_SET_VER, %o5
mov %o3, %o4
ta HV_CORE_TRAP
retl
stx %o1, [%o4]
- .size sun4v_set_version, .-sun4v_set_version
+ENDPROC(sun4v_set_version)
/* %o0: pointer to unsigned long time
*
* returns %o0: status
*/
- .globl sun4v_tod_get
- .type sun4v_tod_get,#function
-sun4v_tod_get:
+ENTRY(sun4v_tod_get)
mov %o0, %o4
mov HV_FAST_TOD_GET, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_tod_get, .-sun4v_tod_get
+ENDPROC(sun4v_tod_get)
/* %o0: time
*
* returns %o0: status
*/
- .globl sun4v_tod_set
- .type sun4v_tod_set,#function
-sun4v_tod_set:
+ENTRY(sun4v_tod_set)
mov HV_FAST_TOD_SET, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_tod_set, .-sun4v_tod_set
+ENDPROC(sun4v_tod_set)
/* %o0: pointer to unsigned long status
*
* returns %o0: signed character
*/
- .globl sun4v_con_getchar
- .type sun4v_con_getchar,#function
-sun4v_con_getchar:
+ENTRY(sun4v_con_getchar)
mov %o0, %o4
mov HV_FAST_CONS_GETCHAR, %o5
clr %o0
@@ -281,20 +241,18 @@ sun4v_con_getchar:
stx %o0, [%o4]
retl
sra %o1, 0, %o0
- .size sun4v_con_getchar, .-sun4v_con_getchar
+ENDPROC(sun4v_con_getchar)
/* %o0: signed long character
*
* returns %o0: status
*/
- .globl sun4v_con_putchar
- .type sun4v_con_putchar,#function
-sun4v_con_putchar:
+ENTRY(sun4v_con_putchar)
mov HV_FAST_CONS_PUTCHAR, %o5
ta HV_FAST_TRAP
retl
sra %o0, 0, %o0
- .size sun4v_con_putchar, .-sun4v_con_putchar
+ENDPROC(sun4v_con_putchar)
/* %o0: buffer real address
* %o1: buffer size
@@ -302,9 +260,7 @@ sun4v_con_putchar:
*
* returns %o0: status
*/
- .globl sun4v_con_read
- .type sun4v_con_read,#function
-sun4v_con_read:
+ENTRY(sun4v_con_read)
mov %o2, %o4
mov HV_FAST_CONS_READ, %o5
ta HV_FAST_TRAP
@@ -318,7 +274,7 @@ sun4v_con_read:
stx %o1, [%o4]
1: retl
nop
- .size sun4v_con_read, .-sun4v_con_read
+ENDPROC(sun4v_con_read)
/* %o0: buffer real address
* %o1: buffer size
@@ -326,43 +282,37 @@ sun4v_con_read:
*
* returns %o0: status
*/
- .globl sun4v_con_write
- .type sun4v_con_write,#function
-sun4v_con_write:
+ENTRY(sun4v_con_write)
mov %o2, %o4
mov HV_FAST_CONS_WRITE, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_con_write, .-sun4v_con_write
+ENDPROC(sun4v_con_write)
/* %o0: soft state
* %o1: address of description string
*
* returns %o0: status
*/
- .globl sun4v_mach_set_soft_state
- .type sun4v_mach_set_soft_state,#function
-sun4v_mach_set_soft_state:
+ENTRY(sun4v_mach_set_soft_state)
mov HV_FAST_MACH_SET_SOFT_STATE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
+ENDPROC(sun4v_mach_set_soft_state)
/* %o0: exit code
*
* Does not return.
*/
- .globl sun4v_mach_exit
- .type sun4v_mach_exit,#function
-sun4v_mach_exit:
+ENTRY(sun4v_mach_exit)
mov HV_FAST_MACH_EXIT, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mach_exit, .-sun4v_mach_exit
+ENDPROC(sun4v_mach_exit)
/* %o0: buffer real address
* %o1: buffer length
@@ -370,44 +320,38 @@ sun4v_mach_exit:
*
* returns %o0: status
*/
- .globl sun4v_mach_desc
- .type sun4v_mach_desc,#function
-sun4v_mach_desc:
+ENTRY(sun4v_mach_desc)
mov %o2, %o4
mov HV_FAST_MACH_DESC, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mach_desc, .-sun4v_mach_desc
+ENDPROC(sun4v_mach_desc)
/* %o0: new timeout in milliseconds
* %o1: pointer to unsigned long orig_timeout
*
* returns %o0: status
*/
- .globl sun4v_mach_set_watchdog
- .type sun4v_mach_set_watchdog,#function
-sun4v_mach_set_watchdog:
+ENTRY(sun4v_mach_set_watchdog)
mov %o1, %o4
mov HV_FAST_MACH_SET_WATCHDOG, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
+ENDPROC(sun4v_mach_set_watchdog)
/* No inputs and does not return. */
- .globl sun4v_mach_sir
- .type sun4v_mach_sir,#function
-sun4v_mach_sir:
+ENTRY(sun4v_mach_sir)
mov %o1, %o4
mov HV_FAST_MACH_SIR, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mach_sir, .-sun4v_mach_sir
+ENDPROC(sun4v_mach_sir)
/* %o0: channel
* %o1: ra
@@ -415,14 +359,12 @@ sun4v_mach_sir:
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_qconf
- .type sun4v_ldc_tx_qconf,#function
-sun4v_ldc_tx_qconf:
+ENTRY(sun4v_ldc_tx_qconf)
mov HV_FAST_LDC_TX_QCONF, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
+ENDPROC(sun4v_ldc_tx_qconf)
/* %o0: channel
* %o1: pointer to unsigned long ra
@@ -430,9 +372,7 @@ sun4v_ldc_tx_qconf:
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_qinfo
- .type sun4v_ldc_tx_qinfo,#function
-sun4v_ldc_tx_qinfo:
+ENTRY(sun4v_ldc_tx_qinfo)
mov %o1, %g1
mov %o2, %g2
mov HV_FAST_LDC_TX_QINFO, %o5
@@ -441,7 +381,7 @@ sun4v_ldc_tx_qinfo:
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
+ENDPROC(sun4v_ldc_tx_qinfo)
/* %o0: channel
* %o1: pointer to unsigned long head_off
@@ -450,9 +390,7 @@ sun4v_ldc_tx_qinfo:
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_get_state
- .type sun4v_ldc_tx_get_state,#function
-sun4v_ldc_tx_get_state:
+ENTRY(sun4v_ldc_tx_get_state)
mov %o1, %g1
mov %o2, %g2
mov %o3, %g3
@@ -463,21 +401,19 @@ sun4v_ldc_tx_get_state:
stx %o3, [%g3]
retl
nop
- .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
+ENDPROC(sun4v_ldc_tx_get_state)
/* %o0: channel
* %o1: tail_off
*
* returns %o0: status
*/
- .globl sun4v_ldc_tx_set_qtail
- .type sun4v_ldc_tx_set_qtail,#function
-sun4v_ldc_tx_set_qtail:
+ENTRY(sun4v_ldc_tx_set_qtail)
mov HV_FAST_LDC_TX_SET_QTAIL, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
+ENDPROC(sun4v_ldc_tx_set_qtail)
/* %o0: channel
* %o1: ra
@@ -485,14 +421,12 @@ sun4v_ldc_tx_set_qtail:
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_qconf
- .type sun4v_ldc_rx_qconf,#function
-sun4v_ldc_rx_qconf:
+ENTRY(sun4v_ldc_rx_qconf)
mov HV_FAST_LDC_RX_QCONF, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
+ENDPROC(sun4v_ldc_rx_qconf)
/* %o0: channel
* %o1: pointer to unsigned long ra
@@ -500,9 +434,7 @@ sun4v_ldc_rx_qconf:
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_qinfo
- .type sun4v_ldc_rx_qinfo,#function
-sun4v_ldc_rx_qinfo:
+ENTRY(sun4v_ldc_rx_qinfo)
mov %o1, %g1
mov %o2, %g2
mov HV_FAST_LDC_RX_QINFO, %o5
@@ -511,7 +443,7 @@ sun4v_ldc_rx_qinfo:
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
+ENDPROC(sun4v_ldc_rx_qinfo)
/* %o0: channel
* %o1: pointer to unsigned long head_off
@@ -520,9 +452,7 @@ sun4v_ldc_rx_qinfo:
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_get_state
- .type sun4v_ldc_rx_get_state,#function
-sun4v_ldc_rx_get_state:
+ENTRY(sun4v_ldc_rx_get_state)
mov %o1, %g1
mov %o2, %g2
mov %o3, %g3
@@ -533,21 +463,19 @@ sun4v_ldc_rx_get_state:
stx %o3, [%g3]
retl
nop
- .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
+ENDPROC(sun4v_ldc_rx_get_state)
/* %o0: channel
* %o1: head_off
*
* returns %o0: status
*/
- .globl sun4v_ldc_rx_set_qhead
- .type sun4v_ldc_rx_set_qhead,#function
-sun4v_ldc_rx_set_qhead:
+ENTRY(sun4v_ldc_rx_set_qhead)
mov HV_FAST_LDC_RX_SET_QHEAD, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
+ENDPROC(sun4v_ldc_rx_set_qhead)
/* %o0: channel
* %o1: ra
@@ -555,14 +483,12 @@ sun4v_ldc_rx_set_qhead:
*
* returns %o0: status
*/
- .globl sun4v_ldc_set_map_table
- .type sun4v_ldc_set_map_table,#function
-sun4v_ldc_set_map_table:
+ENTRY(sun4v_ldc_set_map_table)
mov HV_FAST_LDC_SET_MAP_TABLE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
+ENDPROC(sun4v_ldc_set_map_table)
/* %o0: channel
* %o1: pointer to unsigned long ra
@@ -570,9 +496,7 @@ sun4v_ldc_set_map_table:
*
* returns %o0: status
*/
- .globl sun4v_ldc_get_map_table
- .type sun4v_ldc_get_map_table,#function
-sun4v_ldc_get_map_table:
+ENTRY(sun4v_ldc_get_map_table)
mov %o1, %g1
mov %o2, %g2
mov HV_FAST_LDC_GET_MAP_TABLE, %o5
@@ -581,7 +505,7 @@ sun4v_ldc_get_map_table:
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
+ENDPROC(sun4v_ldc_get_map_table)
/* %o0: channel
* %o1: dir_code
@@ -592,16 +516,14 @@ sun4v_ldc_get_map_table:
*
* returns %o0: status
*/
- .globl sun4v_ldc_copy
- .type sun4v_ldc_copy,#function
-sun4v_ldc_copy:
+ENTRY(sun4v_ldc_copy)
mov %o5, %g1
mov HV_FAST_LDC_COPY, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_ldc_copy, .-sun4v_ldc_copy
+ENDPROC(sun4v_ldc_copy)
/* %o0: channel
* %o1: cookie
@@ -610,9 +532,7 @@ sun4v_ldc_copy:
*
* returns %o0: status
*/
- .globl sun4v_ldc_mapin
- .type sun4v_ldc_mapin,#function
-sun4v_ldc_mapin:
+ENTRY(sun4v_ldc_mapin)
mov %o2, %g1
mov %o3, %g2
mov HV_FAST_LDC_MAPIN, %o5
@@ -621,20 +541,18 @@ sun4v_ldc_mapin:
stx %o2, [%g2]
retl
nop
- .size sun4v_ldc_mapin, .-sun4v_ldc_mapin
+ENDPROC(sun4v_ldc_mapin)
/* %o0: ra
*
* returns %o0: status
*/
- .globl sun4v_ldc_unmap
- .type sun4v_ldc_unmap,#function
-sun4v_ldc_unmap:
+ENTRY(sun4v_ldc_unmap)
mov HV_FAST_LDC_UNMAP, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_unmap, .-sun4v_ldc_unmap
+ENDPROC(sun4v_ldc_unmap)
/* %o0: channel
* %o1: cookie
@@ -642,14 +560,12 @@ sun4v_ldc_unmap:
*
* returns %o0: status
*/
- .globl sun4v_ldc_revoke
- .type sun4v_ldc_revoke,#function
-sun4v_ldc_revoke:
+ENTRY(sun4v_ldc_revoke)
mov HV_FAST_LDC_REVOKE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ldc_revoke, .-sun4v_ldc_revoke
+ENDPROC(sun4v_ldc_revoke)
/* %o0: device handle
* %o1: device INO
@@ -657,16 +573,14 @@ sun4v_ldc_revoke:
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_cookie
- .type sun4v_vintr_get_cookie,#function
-sun4v_vintr_get_cookie:
+ENTRY(sun4v_vintr_get_cookie)
mov %o2, %g1
mov HV_FAST_VINTR_GET_COOKIE, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
+ENDPROC(sun4v_vintr_get_cookie)
/* %o0: device handle
* %o1: device INO
@@ -674,14 +588,12 @@ sun4v_vintr_get_cookie:
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_cookie
- .type sun4v_vintr_set_cookie,#function
-sun4v_vintr_set_cookie:
+ENTRY(sun4v_vintr_set_cookie)
mov HV_FAST_VINTR_SET_COOKIE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
+ENDPROC(sun4v_vintr_set_cookie)
/* %o0: device handle
* %o1: device INO
@@ -689,16 +601,14 @@ sun4v_vintr_set_cookie:
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_valid
- .type sun4v_vintr_get_valid,#function
-sun4v_vintr_get_valid:
+ENTRY(sun4v_vintr_get_valid)
mov %o2, %g1
mov HV_FAST_VINTR_GET_VALID, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
+ENDPROC(sun4v_vintr_get_valid)
/* %o0: device handle
* %o1: device INO
@@ -706,14 +616,12 @@ sun4v_vintr_get_valid:
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_valid
- .type sun4v_vintr_set_valid,#function
-sun4v_vintr_set_valid:
+ENTRY(sun4v_vintr_set_valid)
mov HV_FAST_VINTR_SET_VALID, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
+ENDPROC(sun4v_vintr_set_valid)
/* %o0: device handle
* %o1: device INO
@@ -721,16 +629,14 @@ sun4v_vintr_set_valid:
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_state
- .type sun4v_vintr_get_state,#function
-sun4v_vintr_get_state:
+ENTRY(sun4v_vintr_get_state)
mov %o2, %g1
mov HV_FAST_VINTR_GET_STATE, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_state, .-sun4v_vintr_get_state
+ENDPROC(sun4v_vintr_get_state)
/* %o0: device handle
* %o1: device INO
@@ -738,14 +644,12 @@ sun4v_vintr_get_state:
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_state
- .type sun4v_vintr_set_state,#function
-sun4v_vintr_set_state:
+ENTRY(sun4v_vintr_set_state)
mov HV_FAST_VINTR_SET_STATE, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_state, .-sun4v_vintr_set_state
+ENDPROC(sun4v_vintr_set_state)
/* %o0: device handle
* %o1: device INO
@@ -753,16 +657,14 @@ sun4v_vintr_set_state:
*
* returns %o0: status
*/
- .globl sun4v_vintr_get_target
- .type sun4v_vintr_get_target,#function
-sun4v_vintr_get_target:
+ENTRY(sun4v_vintr_get_target)
mov %o2, %g1
mov HV_FAST_VINTR_GET_TARGET, %o5
ta HV_FAST_TRAP
stx %o1, [%g1]
retl
nop
- .size sun4v_vintr_get_target, .-sun4v_vintr_get_target
+ENDPROC(sun4v_vintr_get_target)
/* %o0: device handle
* %o1: device INO
@@ -770,14 +672,12 @@ sun4v_vintr_get_target:
*
* returns %o0: status
*/
- .globl sun4v_vintr_set_target
- .type sun4v_vintr_set_target,#function
-sun4v_vintr_set_target:
+ENTRY(sun4v_vintr_set_target)
mov HV_FAST_VINTR_SET_TARGET, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_vintr_set_target, .-sun4v_vintr_set_target
+ENDPROC(sun4v_vintr_set_target)
/* %o0: NCS sub-function
* %o1: sub-function arg real-address
@@ -785,18 +685,14 @@ sun4v_vintr_set_target:
*
* returns %o0: status
*/
- .globl sun4v_ncs_request
- .type sun4v_ncs_request,#function
-sun4v_ncs_request:
+ENTRY(sun4v_ncs_request)
mov HV_FAST_NCS_REQUEST, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_ncs_request, .-sun4v_ncs_request
+ENDPROC(sun4v_ncs_request)
- .globl sun4v_svc_send
- .type sun4v_svc_send,#function
-sun4v_svc_send:
+ENTRY(sun4v_svc_send)
save %sp, -192, %sp
mov %i0, %o0
mov %i1, %o1
@@ -806,11 +702,9 @@ sun4v_svc_send:
stx %o1, [%i3]
ret
restore
- .size sun4v_svc_send, .-sun4v_svc_send
+ENDPROC(sun4v_svc_send)
- .globl sun4v_svc_recv
- .type sun4v_svc_recv,#function
-sun4v_svc_recv:
+ENTRY(sun4v_svc_recv)
save %sp, -192, %sp
mov %i0, %o0
mov %i1, %o1
@@ -820,62 +714,50 @@ sun4v_svc_recv:
stx %o1, [%i3]
ret
restore
- .size sun4v_svc_recv, .-sun4v_svc_recv
+ENDPROC(sun4v_svc_recv)
- .globl sun4v_svc_getstatus
- .type sun4v_svc_getstatus,#function
-sun4v_svc_getstatus:
+ENTRY(sun4v_svc_getstatus)
mov HV_FAST_SVC_GETSTATUS, %o5
mov %o1, %o4
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_svc_getstatus, .-sun4v_svc_getstatus
+ENDPROC(sun4v_svc_getstatus)
- .globl sun4v_svc_setstatus
- .type sun4v_svc_setstatus,#function
-sun4v_svc_setstatus:
+ENTRY(sun4v_svc_setstatus)
mov HV_FAST_SVC_SETSTATUS, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_svc_setstatus, .-sun4v_svc_setstatus
+ENDPROC(sun4v_svc_setstatus)
- .globl sun4v_svc_clrstatus
- .type sun4v_svc_clrstatus,#function
-sun4v_svc_clrstatus:
+ENTRY(sun4v_svc_clrstatus)
mov HV_FAST_SVC_CLRSTATUS, %o5
ta HV_FAST_TRAP
retl
nop
- .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus
+ENDPROC(sun4v_svc_clrstatus)
- .globl sun4v_mmustat_conf
- .type sun4v_mmustat_conf,#function
-sun4v_mmustat_conf:
+ENTRY(sun4v_mmustat_conf)
mov %o1, %o4
mov HV_FAST_MMUSTAT_CONF, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mmustat_conf, .-sun4v_mmustat_conf
+ENDPROC(sun4v_mmustat_conf)
- .globl sun4v_mmustat_info
- .type sun4v_mmustat_info,#function
-sun4v_mmustat_info:
+ENTRY(sun4v_mmustat_info)
mov %o0, %o4
mov HV_FAST_MMUSTAT_INFO, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
- .size sun4v_mmustat_info, .-sun4v_mmustat_info
+ENDPROC(sun4v_mmustat_info)
- .globl sun4v_mmu_demap_all
- .type sun4v_mmu_demap_all,#function
-sun4v_mmu_demap_all:
+ENTRY(sun4v_mmu_demap_all)
clr %o0
clr %o1
mov HV_MMU_ALL, %o2
@@ -883,4 +765,4 @@ sun4v_mmu_demap_all:
ta HV_FAST_TRAP
retl
nop
- .size sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
+ENDPROC(sun4v_mmu_demap_all)
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 7495bc77468..52fc836f464 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -29,7 +29,6 @@
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 100ebd52749..0f616ae3246 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -55,15 +55,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
}
EXPORT_SYMBOL(of_find_device_by_node);
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+ struct of_device *op = of_find_device_by_node(node);
+
+ if (!op || index >= op->num_irqs)
+ return 0;
+
+ return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+ struct dev_archdata *bus_sd = &bus->dev.archdata;
+ struct device_node *bus_dp = bus->node;
+ struct device_node *dp;
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+ for (dp = bus_dp->child; dp; dp = dp->sibling) {
+ struct of_device *op = of_find_device_by_node(dp);
+
+ op->dev.archdata.iommu = bus_sd->iommu;
+ op->dev.archdata.stc = bus_sd->stc;
+ op->dev.archdata.host_controller = bus_sd->host_controller;
+ op->dev.archdata.numa_node = bus_sd->numa_node;
+
+ if (dp->child)
+ of_propagate_archdata(op);
+ }
+}
struct bus_type of_platform_bus_type;
EXPORT_SYMBOL(of_platform_bus_type);
@@ -378,8 +401,7 @@ static int __init build_one_resource(struct device_node *parent,
int na, int ns, int pna)
{
const u32 *ranges;
- unsigned int rlen;
- int rone;
+ int rone, rlen;
ranges = of_get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
@@ -421,8 +443,17 @@ static int __init use_1to1_mapping(struct device_node *pp)
/* If the parent is the dma node of an ISA bus, pass
* the translation up to the root.
+ *
+ * Some SBUS devices use intermediate nodes to express
+ * hierarchy within the device itself. These aren't
+ * real bus nodes, and don't have a 'ranges' property.
+ * But, we should still pass the translation work up
+ * to the SBUS itself.
*/
- if (!strcmp(pp->name, "dma"))
+ if (!strcmp(pp->name, "dma") ||
+ !strcmp(pp->name, "espdma") ||
+ !strcmp(pp->name, "ledma") ||
+ !strcmp(pp->name, "lebuffer"))
return 0;
/* Similarly for all PCI bridges, if we get this far
@@ -844,15 +875,6 @@ static int __init of_bus_driver_init(void)
int err;
err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
- if (!err)
- err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
- if (!err)
- err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
if (!err)
scan_of_devices();
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 80dad76f8b8..242ac1ccae7 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -18,32 +18,17 @@
#include <linux/msi.h>
#include <linux/irq.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
-#include <asm/ebus.h>
#include <asm/prom.h>
#include <asm/apb.h>
#include "pci_impl.h"
-#ifndef CONFIG_PCI
-/* A "nop" PCI implementation. */
-asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len,
- unsigned char *buf)
-{
- return 0;
-}
-asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len,
- unsigned char *buf)
-{
- return 0;
-}
-#else
-
/* List of all PCI controllers found in the system. */
struct pci_pbm_info *pci_pbm_root = NULL;
@@ -179,97 +164,6 @@ void pci_config_write32(u32 *addr, u32 val)
spin_unlock_irqrestore(&pci_poke_lock, flags);
}
-/* Probe for all PCI controllers in the system. */
-extern void sabre_init(struct device_node *, const char *);
-extern void psycho_init(struct device_node *, const char *);
-extern void schizo_init(struct device_node *, const char *);
-extern void schizo_plus_init(struct device_node *, const char *);
-extern void tomatillo_init(struct device_node *, const char *);
-extern void sun4v_pci_init(struct device_node *, const char *);
-extern void fire_pci_init(struct device_node *, const char *);
-
-static struct {
- char *model_name;
- void (*init)(struct device_node *, const char *);
-} pci_controller_table[] __initdata = {
- { "SUNW,sabre", sabre_init },
- { "pci108e,a000", sabre_init },
- { "pci108e,a001", sabre_init },
- { "SUNW,psycho", psycho_init },
- { "pci108e,8000", psycho_init },
- { "SUNW,schizo", schizo_init },
- { "pci108e,8001", schizo_init },
- { "SUNW,schizo+", schizo_plus_init },
- { "pci108e,8002", schizo_plus_init },
- { "SUNW,tomatillo", tomatillo_init },
- { "pci108e,a801", tomatillo_init },
- { "SUNW,sun4v-pci", sun4v_pci_init },
- { "pciex108e,80f0", fire_pci_init },
-};
-#define PCI_NUM_CONTROLLER_TYPES ARRAY_SIZE(pci_controller_table)
-
-static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
-{
- int i;
-
- for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {
- if (!strncmp(model_name,
- pci_controller_table[i].model_name,
- namelen)) {
- pci_controller_table[i].init(dp, model_name);
- return 1;
- }
- }
-
- return 0;
-}
-
-static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
-{
- struct device_node *dp;
- int count = 0;
-
- for_each_node_by_name(dp, "pci") {
- struct property *prop;
- int len;
-
- prop = of_find_property(dp, "model", &len);
- if (!prop)
- prop = of_find_property(dp, "compatible", &len);
-
- if (prop) {
- const char *model = prop->value;
- int item_len = 0;
-
- /* Our value may be a multi-valued string in the
- * case of some compatible properties. For sanity,
- * only try the first one.
- */
- while (model[item_len] && len) {
- len--;
- item_len++;
- }
-
- if (handler(model, item_len, dp))
- count++;
- }
- }
-
- return count;
-}
-
-/* Find each controller in the system, attach and initialize
- * software state structure for each and link into the
- * pci_pbm_root. Setup the controller enough such
- * that bus scanning can be done.
- */
-static void __init pci_controller_probe(void)
-{
- printk("PCI: Probing for controllers.\n");
-
- pci_controller_scan(pci_controller_init);
-}
-
static int ofpci_verbose;
static int __init ofpci_debug(char *str)
@@ -348,11 +242,12 @@ static void pci_parse_of_addrs(struct of_device *op,
}
}
-struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
- struct device_node *node,
- struct pci_bus *bus, int devfn)
+static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_bus *bus, int devfn)
{
struct dev_archdata *sd;
+ struct of_device *op;
struct pci_dev *dev;
const char *type;
u32 class;
@@ -366,14 +261,17 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
sd->stc = &pbm->stc;
sd->host_controller = pbm;
sd->prom_node = node;
- sd->op = of_find_device_by_node(node);
+ sd->op = op = of_find_device_by_node(node);
sd->numa_node = pbm->numa_node;
- sd = &sd->op->dev.archdata;
+ sd = &op->dev.archdata;
sd->iommu = pbm->iommu;
sd->stc = &pbm->stc;
sd->numa_node = pbm->numa_node;
+ if (!strcmp(node->name, "ebus"))
+ of_propagate_archdata(op);
+
type = of_get_property(node, "device_type", NULL);
if (type == NULL)
type = "";
@@ -775,15 +673,15 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
pci_bus_register_of_sysfs(child_bus);
}
-struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
+struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
+ struct device *parent)
{
- struct device_node *node = pbm->prom_node;
+ struct device_node *node = pbm->op->node;
struct pci_bus *bus;
printk("PCI: Scanning PBM %s\n", node->full_name);
- /* XXX parent device? XXX */
- bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
+ bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
if (!bus) {
printk(KERN_ERR "Failed to create bus for %s\n",
node->full_name);
@@ -802,32 +700,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
return bus;
}
-static void __init pci_scan_each_controller_bus(void)
-{
- struct pci_pbm_info *pbm;
-
- for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
- pbm->scan_bus(pbm);
-}
-
-extern void power_init(void);
-
-static int __init pcibios_init(void)
-{
- pci_controller_probe();
- if (pci_pbm_root == NULL)
- return 0;
-
- pci_scan_each_controller_bus();
-
- ebus_init();
- power_init();
-
- return 0;
-}
-
-subsys_initcall(pcibios_init);
-
void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
{
struct pci_pbm_info *pbm = pbus->sysdata;
@@ -1105,14 +977,14 @@ int pcibus_to_node(struct pci_bus *pbus)
EXPORT_SYMBOL(pcibus_to_node);
#endif
-/* Return the domain nuber for this pci bus */
+/* Return the domain number for this pci bus */
int pci_domain_nr(struct pci_bus *pbus)
{
struct pci_pbm_info *pbm = pbus->sysdata;
int ret;
- if (pbm == NULL || pbm->parent == NULL) {
+ if (!pbm) {
ret = -ENXIO;
} else {
ret = pbm->index;
@@ -1126,7 +998,7 @@ EXPORT_SYMBOL(pci_domain_nr);
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- int virt_irq;
+ unsigned int virt_irq;
if (!pbm->setup_msi_irq)
return -EINVAL;
@@ -1140,10 +1012,8 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
struct pci_dev *pdev = entry->dev;
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- if (!pbm->teardown_msi_irq)
- return;
-
- return pbm->teardown_msi_irq(virt_irq, pdev);
+ if (pbm->teardown_msi_irq)
+ pbm->teardown_msi_irq(virt_irq, pdev);
}
#endif /* !(CONFIG_PCI_MSI) */
@@ -1215,5 +1085,3 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
*start = rp->start - offset;
*end = rp->end - offset;
}
-
-#endif /* !(CONFIG_PCI) */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 09a5ec200c6..23b88082d0b 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -314,12 +314,12 @@ struct pci_ops sun4v_pci_ops = {
void pci_get_pbm_props(struct pci_pbm_info *pbm)
{
- const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
+ const u32 *val = of_get_property(pbm->op->node, "bus-range", NULL);
pbm->pci_first_busno = val[0];
pbm->pci_last_busno = val[1];
- val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
+ val = of_get_property(pbm->op->node, "ino-bitmap", NULL);
if (val) {
pbm->ino_bitmap = (((u64)val[1] << 32UL) |
((u64)val[0] << 0UL));
@@ -365,7 +365,7 @@ static void pci_register_legacy_regions(struct resource *io_res,
static void pci_register_iommu_region(struct pci_pbm_info *pbm)
{
- const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
+ const u32 *vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
if (vdma) {
struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
@@ -389,7 +389,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
int num_pbm_ranges;
saw_mem = saw_io = 0;
- pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
+ pbm_ranges = of_get_property(pbm->op->node, "ranges", &i);
if (!pbm_ranges) {
prom_printf("PCI: Fatal error, missing PBM ranges property "
" for %s\n",
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index d23bb6f53cd..9462b68f489 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -8,34 +8,16 @@
#include <linux/init.h>
#include <linux/msi.h>
#include <linux/irq.h>
+#include <linux/of_device.h>
-#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/irq.h>
+#include <asm/upa.h>
#include "pci_impl.h"
-#define fire_read(__reg) \
-({ u64 __ret; \
- __asm__ __volatile__("ldxa [%1] %2, %0" \
- : "=r" (__ret) \
- : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory"); \
- __ret; \
-})
-#define fire_write(__reg, __val) \
- __asm__ __volatile__("stxa %0, [%1] %2" \
- : /* no outputs */ \
- : "r" (__val), "r" (__reg), \
- "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory")
-
-static void __init pci_fire_scan_bus(struct pci_pbm_info *pbm)
-{
- pbm->pci_bus = pci_scan_one_pbm(pbm);
-
- /* XXX register error interrupt handlers XXX */
-}
+#define DRIVER_NAME "fire"
+#define PFX DRIVER_NAME ": "
#define FIRE_IOMMU_CONTROL 0x40000UL
#define FIRE_IOMMU_TSBBASE 0x40008UL
@@ -69,21 +51,21 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
/*
* Invalidate TLB Entries.
*/
- fire_write(iommu->iommu_flushinv, ~(u64)0);
+ upa_writeq(~(u64)0, iommu->iommu_flushinv);
err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
pbm->numa_node);
if (err)
return err;
- fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
+ upa_writeq(__pa(iommu->page_table) | 0x7UL, iommu->iommu_tsbbase);
- control = fire_read(iommu->iommu_control);
+ control = upa_readq(iommu->iommu_control);
control |= (0x00000400 /* TSB cache snoop enable */ |
0x00000300 /* Cache mode */ |
0x00000002 /* Bypass enable */ |
0x00000001 /* Translation enable */);
- fire_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
return 0;
}
@@ -165,7 +147,7 @@ struct pci_msiq_entry {
static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long *head)
{
- *head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
+ *head = upa_readq(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
return 0;
}
@@ -191,8 +173,7 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
*msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
MSIQ_WORD0_DATA0_SHIFT);
- fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
- MSI_CLEAR_EQWR_N);
+ upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi_num));
/* Clear the entry. */
ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
@@ -208,7 +189,7 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long head)
{
- fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
+ upa_writeq(head, pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
return 0;
}
@@ -217,17 +198,16 @@ static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
{
u64 val;
- val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
val &= ~(MSI_MAP_EQNUM);
val |= msiqid;
- fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+ upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
- fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
- MSI_CLEAR_EQWR_N);
+ upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi));
- val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
val |= MSI_MAP_VALID;
- fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+ upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
return 0;
}
@@ -237,12 +217,12 @@ static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
unsigned long msiqid;
u64 val;
- val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+ val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
msiqid = (val & MSI_MAP_EQNUM);
val &= ~MSI_MAP_VALID;
- fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+ upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
return 0;
}
@@ -261,22 +241,19 @@ static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm)
memset((char *)pages, 0, PAGE_SIZE << order);
pbm->msi_queues = (void *) pages;
- fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
- (EVENT_QUEUE_BASE_ADDR_ALL_ONES |
- __pa(pbm->msi_queues)));
+ upa_writeq((EVENT_QUEUE_BASE_ADDR_ALL_ONES |
+ __pa(pbm->msi_queues)),
+ pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG);
- fire_write(pbm->pbm_regs + IMONDO_DATA0,
- pbm->portid << 6);
- fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
+ upa_writeq(pbm->portid << 6, pbm->pbm_regs + IMONDO_DATA0);
+ upa_writeq(0, pbm->pbm_regs + IMONDO_DATA1);
- fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
- pbm->msi32_start);
- fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
- pbm->msi64_start);
+ upa_writeq(pbm->msi32_start, pbm->pbm_regs + MSI_32BIT_ADDR);
+ upa_writeq(pbm->msi64_start, pbm->pbm_regs + MSI_64BIT_ADDR);
for (i = 0; i < pbm->msiq_num; i++) {
- fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
- fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
+ upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_HEAD(i));
+ upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_TAIL(i));
}
return 0;
@@ -310,9 +287,9 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
/* XXX iterate amongst the 4 IRQ controllers XXX */
int_ctrlr = (1UL << 6);
- val = fire_read(imap_reg);
+ val = upa_readq(imap_reg);
val |= (1UL << 63) | int_ctrlr;
- fire_write(imap_reg, val);
+ upa_writeq(val, imap_reg);
fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
@@ -320,9 +297,8 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
if (!virt_irq)
return -ENOMEM;
- fire_write(pbm->pbm_regs +
- EVENT_QUEUE_CONTROL_SET(msiqid),
- EVENT_QUEUE_CONTROL_SET_EN);
+ upa_writeq(EVENT_QUEUE_CONTROL_SET_EN,
+ pbm->pbm_regs + EVENT_QUEUE_CONTROL_SET(msiqid));
return virt_irq;
}
@@ -390,77 +366,65 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
{
u64 val;
- fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
- FIRE_PARITY_ENAB);
+ upa_writeq(FIRE_PARITY_ENAB,
+ pbm->controller_regs + FIRE_PARITY_CONTROL);
- fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
- (FIRE_FATAL_RESET_SPARE |
+ upa_writeq((FIRE_FATAL_RESET_SPARE |
FIRE_FATAL_RESET_MB |
FIRE_FATAL_RESET_CPE |
FIRE_FATAL_RESET_APE |
FIRE_FATAL_RESET_PIO |
FIRE_FATAL_RESET_JW |
FIRE_FATAL_RESET_JI |
- FIRE_FATAL_RESET_JR));
+ FIRE_FATAL_RESET_JR),
+ pbm->controller_regs + FIRE_FATAL_RESET_CTL);
- fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
+ upa_writeq(~(u64)0, pbm->controller_regs + FIRE_CORE_INTR_ENABLE);
- val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL);
+ val = upa_readq(pbm->pbm_regs + FIRE_TLU_CTRL);
val |= (FIRE_TLU_CTRL_TIM |
FIRE_TLU_CTRL_QDET |
FIRE_TLU_CTRL_CFG);
- fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val);
- fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0);
- fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL,
- FIRE_TLU_LINK_CTRL_CLK);
-
- fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0);
- fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG,
- FIRE_LPU_LLCFG_VC0);
- fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL,
- (FIRE_LPU_FCTRL_UCTRL_N |
- FIRE_LPU_FCTRL_UCTRL_P));
- fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP,
- ((0xffff << 16) | (0x0000 << 0)));
- fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000);
- fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000);
- fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4,
- (2 << 16) | (140 << 8));
- fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0);
-
- fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0);
- fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0);
- fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0);
-
- fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
+ upa_writeq(val, pbm->pbm_regs + FIRE_TLU_CTRL);
+ upa_writeq(0, pbm->pbm_regs + FIRE_TLU_DEV_CTRL);
+ upa_writeq(FIRE_TLU_LINK_CTRL_CLK,
+ pbm->pbm_regs + FIRE_TLU_LINK_CTRL);
+
+ upa_writeq(0, pbm->pbm_regs + FIRE_LPU_RESET);
+ upa_writeq(FIRE_LPU_LLCFG_VC0, pbm->pbm_regs + FIRE_LPU_LLCFG);
+ upa_writeq((FIRE_LPU_FCTRL_UCTRL_N | FIRE_LPU_FCTRL_UCTRL_P),
+ pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL);
+ upa_writeq(((0xffff << 16) | (0x0000 << 0)),
+ pbm->pbm_regs + FIRE_LPU_TXL_FIFOP);
+ upa_writeq(3000000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2);
+ upa_writeq(500000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3);
+ upa_writeq((2 << 16) | (140 << 8),
+ pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4);
+ upa_writeq(0, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5);
+
+ upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_DMC_IENAB);
+ upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_A);
+ upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_B);
+
+ upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB);
}
-static int __init pci_fire_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid)
+static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, u32 portid)
{
const struct linux_prom64_registers *regs;
- struct pci_pbm_info *pbm;
+ struct device_node *dp = op->node;
int err;
- if ((portid & 1) == 0)
- pbm = &p->pbm_A;
- else
- pbm = &p->pbm_B;
-
- pbm->next = pci_pbm_root;
- pci_pbm_root = pbm;
-
pbm->numa_node = -1;
- pbm->scan_bus = pci_fire_scan_bus;
pbm->pci_ops = &sun4u_pci_ops;
pbm->config_space_reg_bits = 12;
pbm->index = pci_num_pbms++;
pbm->portid = portid;
- pbm->parent = p;
- pbm->prom_node = dp;
+ pbm->op = op;
pbm->name = dp->full_name;
regs = of_get_property(dp, "reg", NULL);
@@ -481,53 +445,77 @@ static int __init pci_fire_pbm_init(struct pci_controller_info *p,
pci_fire_msi_init(pbm);
- return 0;
-}
+ pbm->pci_bus = pci_scan_one_pbm(pbm, &op->dev);
+
+ /* XXX register error interrupt handlers XXX */
+
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
-static inline int portid_compare(u32 x, u32 y)
-{
- if (x == (y ^ 1))
- return 1;
return 0;
}
-void __init fire_pci_init(struct device_node *dp, const char *model_name)
+static int __devinit fire_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct pci_controller_info *p;
- u32 portid = of_getintprop_default(dp, "portid", 0xff);
- struct iommu *iommu;
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
+ struct iommu *iommu;
+ u32 portid;
+ int err;
- for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
- if (portid_compare(pbm->portid, portid)) {
- if (pci_fire_pbm_init(pbm->parent, dp, portid))
- goto fatal_memory_error;
- return;
- }
+ portid = of_getintprop_default(dp, "portid", 0xff);
+
+ err = -ENOMEM;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n");
+ goto out_err;
}
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+ goto out_free_controller;
+ }
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ pbm->iommu = iommu;
- p->pbm_A.iommu = iommu;
+ err = pci_fire_pbm_init(pbm, op, portid);
+ if (err)
+ goto out_free_iommu;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ dev_set_drvdata(&op->dev, pbm);
- p->pbm_B.iommu = iommu;
+ return 0;
- if (pci_fire_pbm_init(p, dp, portid))
- goto fatal_memory_error;
+out_free_iommu:
+ kfree(pbm->iommu);
+
+out_free_controller:
+ kfree(pbm);
- return;
+out_err:
+ return err;
+}
+
+static struct of_device_id __initdata fire_match[] = {
+ {
+ .name = "pci",
+ .compatible = "pciex108e,80f0",
+ },
+ {},
+};
-fatal_memory_error:
- prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
- prom_halt();
+static struct of_platform_driver fire_driver = {
+ .name = DRIVER_NAME,
+ .match_table = fire_match,
+ .probe = fire_probe,
+};
+
+static int __init fire_init(void)
+{
+ return of_register_driver(&fire_driver, &of_bus_type);
}
+
+subsys_initcall(fire_init);
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index c385d126be1..03186824327 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -10,6 +10,7 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/msi.h>
+#include <linux/of_device.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/iommu.h>
@@ -56,15 +57,11 @@ struct sparc64_msiq_cookie {
};
#endif
-struct pci_controller_info;
-
struct pci_pbm_info {
struct pci_pbm_info *next;
+ struct pci_pbm_info *sibling;
int index;
- /* PCI controller we sit under. */
- struct pci_controller_info *parent;
-
/* Physical address base of controller registers. */
unsigned long controller_regs;
@@ -94,7 +91,7 @@ struct pci_pbm_info {
char *name;
/* OBP specific information. */
- struct device_node *prom_node;
+ struct of_device *op;
u64 ino_bitmap;
/* PBM I/O and Memory space resources. */
@@ -107,6 +104,10 @@ struct pci_pbm_info {
/* This will be 12 on PCI-E controllers, 8 elsewhere. */
unsigned long config_space_reg_bits;
+ unsigned long pci_afsr;
+ unsigned long pci_afar;
+ unsigned long pci_csr;
+
/* State of 66MHz capabilities on this PBM. */
int is_66mhz_capable;
int all_devs_66mhz;
@@ -146,25 +147,19 @@ struct pci_pbm_info {
unsigned int pci_first_busno;
unsigned int pci_last_busno;
struct pci_bus *pci_bus;
- void (*scan_bus)(struct pci_pbm_info *);
struct pci_ops *pci_ops;
int numa_node;
};
-struct pci_controller_info {
- /* The PCI bus modules controlled by us. */
- struct pci_pbm_info pbm_A;
- struct pci_pbm_info pbm_B;
-};
-
extern struct pci_pbm_info *pci_pbm_root;
extern int pci_num_pbms;
/* PCI bus scanning and fixup support. */
extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
-extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
+extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
+ struct device *parent);
extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
/* Error reporting support. */
@@ -183,4 +178,8 @@ extern void pci_config_write32(u32 *addr, u32 val);
extern struct pci_ops sun4u_pci_ops;
extern struct pci_ops sun4v_pci_ops;
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_cpu;
+extern volatile int pci_poke_faulted;
+
#endif /* !(PCI_IMPL_H) */
diff --git a/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c
index 60c71e35021..2e680f34f72 100644
--- a/arch/sparc64/kernel/pci_msi.c
+++ b/arch/sparc64/kernel/pci_msi.c
@@ -323,7 +323,7 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
const u32 *val;
int len;
- val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+ val = of_get_property(pbm->op->node, "#msi-eqs", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_num = *val;
@@ -346,16 +346,16 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
u32 msi64_len;
} *arng;
- val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+ val = of_get_property(pbm->op->node, "msi-eq-size", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_ent_count = *val;
- mqp = of_get_property(pbm->prom_node,
+ mqp = of_get_property(pbm->op->node,
"msi-eq-to-devino", &len);
if (!mqp)
- mqp = of_get_property(pbm->prom_node,
+ mqp = of_get_property(pbm->op->node,
"msi-eq-devino", &len);
if (!mqp || len != sizeof(struct msiq_prop))
goto no_msi;
@@ -363,27 +363,27 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
pbm->msiq_first = mqp->first_msiq;
pbm->msiq_first_devino = mqp->first_devino;
- val = of_get_property(pbm->prom_node, "#msi", &len);
+ val = of_get_property(pbm->op->node, "#msi", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_num = *val;
- mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+ mrng = of_get_property(pbm->op->node, "msi-ranges", &len);
if (!mrng || len != sizeof(struct msi_range_prop))
goto no_msi;
pbm->msi_first = mrng->first_msi;
- val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+ val = of_get_property(pbm->op->node, "msi-data-mask", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_data_mask = *val;
- val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+ val = of_get_property(pbm->op->node, "msix-data-width", &len);
if (!val || len != 4)
goto no_msi;
pbm->msix_data_width = *val;
- arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+ arng = of_get_property(pbm->op->node, "msi-address-ranges",
&len);
if (!arng || len != sizeof(struct addr_range_prop))
goto no_msi;
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index f85b6bebb0b..dfb3ec89298 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -17,29 +17,14 @@
#include <asm/irq.h>
#include <asm/starfire.h>
#include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
#include "pci_impl.h"
#include "iommu_common.h"
+#include "psycho_common.h"
-/* All PSYCHO registers are 64-bits. The following accessor
- * routines are how they are accessed. The REG parameter
- * is a physical address.
- */
-#define psycho_read(__reg) \
-({ u64 __ret; \
- __asm__ __volatile__("ldxa [%1] %2, %0" \
- : "=r" (__ret) \
- : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory"); \
- __ret; \
-})
-#define psycho_write(__reg, __val) \
- __asm__ __volatile__("stxa %0, [%1] %2" \
- : /* no outputs */ \
- : "r" (__val), "r" (__reg), \
- "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory")
+#define DRIVER_NAME "psycho"
+#define PFX DRIVER_NAME ": "
/* Misc. PSYCHO PCI controller register offsets and definitions. */
#define PSYCHO_CONTROL 0x0010UL
@@ -67,37 +52,7 @@
#define PSYCHO_PCICTRL_RESV4 0x00000000000000c0UL /* Reserved */
#define PSYCHO_PCICTRL_AEN 0x000000000000003fUL /* PCI DVMA Arbitration Enable */
-/* U2P Programmer's Manual, page 13-55, configuration space
- * address format:
- *
- * 32 24 23 16 15 11 10 8 7 2 1 0
- * ---------------------------------------------------------
- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
- * ---------------------------------------------------------
- */
-#define PSYCHO_CONFIG_BASE(PBM) \
- ((PBM)->config_space | (1UL << 24))
-#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \
- (((unsigned long)(BUS) << 16) | \
- ((unsigned long)(DEVFN) << 8) | \
- ((unsigned long)(REG)))
-
-static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
- unsigned char bus,
- unsigned int devfn,
- int where)
-{
- if (!pbm)
- return NULL;
- return (void *)
- (PSYCHO_CONFIG_BASE(pbm) |
- PSYCHO_CONFIG_ENCODE(bus, devfn, where));
-}
-
/* PSYCHO error handling support. */
-enum psycho_error_type {
- UE_ERR, CE_ERR, PCI_ERR
-};
/* Helper function of IOMMU error checking, which checks out
* the state of the streaming buffers. The IOMMU lock is
@@ -122,129 +77,10 @@ enum psycho_error_type {
#define PSYCHO_STC_DATA_B 0xc000UL
#define PSYCHO_STC_ERR_A 0xb400UL
#define PSYCHO_STC_ERR_B 0xc400UL
-#define PSYCHO_STCERR_WRITE 0x0000000000000002UL /* Write Error */
-#define PSYCHO_STCERR_READ 0x0000000000000001UL /* Read Error */
#define PSYCHO_STC_TAG_A 0xb800UL
#define PSYCHO_STC_TAG_B 0xc800UL
-#define PSYCHO_STCTAG_PPN 0x0fffffff00000000UL /* Physical Page Number */
-#define PSYCHO_STCTAG_VPN 0x00000000ffffe000UL /* Virtual Page Number */
-#define PSYCHO_STCTAG_VALID 0x0000000000000002UL /* Valid */
-#define PSYCHO_STCTAG_WRITE 0x0000000000000001UL /* Writable */
#define PSYCHO_STC_LINE_A 0xb900UL
#define PSYCHO_STC_LINE_B 0xc900UL
-#define PSYCHO_STCLINE_LINDX 0x0000000001e00000UL /* LRU Index */
-#define PSYCHO_STCLINE_SPTR 0x00000000001f8000UL /* Dirty Data Start Pointer */
-#define PSYCHO_STCLINE_LADDR 0x0000000000007f00UL /* Line Address */
-#define PSYCHO_STCLINE_EPTR 0x00000000000000fcUL /* Dirty Data End Pointer */
-#define PSYCHO_STCLINE_VALID 0x0000000000000002UL /* Valid */
-#define PSYCHO_STCLINE_FOFN 0x0000000000000001UL /* Fetch Outstanding / Flush Necessary */
-
-static DEFINE_SPINLOCK(stc_buf_lock);
-static unsigned long stc_error_buf[128];
-static unsigned long stc_tag_buf[16];
-static unsigned long stc_line_buf[16];
-
-static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
- int is_pbm_a)
-{
- struct strbuf *strbuf = &pbm->stc;
- unsigned long regbase = pbm->controller_regs;
- unsigned long err_base, tag_base, line_base;
- u64 control;
- int i;
-
- if (is_pbm_a) {
- err_base = regbase + PSYCHO_STC_ERR_A;
- tag_base = regbase + PSYCHO_STC_TAG_A;
- line_base = regbase + PSYCHO_STC_LINE_A;
- } else {
- err_base = regbase + PSYCHO_STC_ERR_B;
- tag_base = regbase + PSYCHO_STC_TAG_B;
- line_base = regbase + PSYCHO_STC_LINE_B;
- }
-
- spin_lock(&stc_buf_lock);
-
- /* This is __REALLY__ dangerous. When we put the
- * streaming buffer into diagnostic mode to probe
- * it's tags and error status, we _must_ clear all
- * of the line tag valid bits before re-enabling
- * the streaming buffer. If any dirty data lives
- * in the STC when we do this, we will end up
- * invalidating it before it has a chance to reach
- * main memory.
- */
- control = psycho_read(strbuf->strbuf_control);
- psycho_write(strbuf->strbuf_control,
- (control | PSYCHO_STRBUF_CTRL_DENAB));
- for (i = 0; i < 128; i++) {
- unsigned long val;
-
- val = psycho_read(err_base + (i * 8UL));
- psycho_write(err_base + (i * 8UL), 0UL);
- stc_error_buf[i] = val;
- }
- for (i = 0; i < 16; i++) {
- stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL));
- stc_line_buf[i] = psycho_read(line_base + (i * 8UL));
- psycho_write(tag_base + (i * 8UL), 0UL);
- psycho_write(line_base + (i * 8UL), 0UL);
- }
-
- /* OK, state is logged, exit diagnostic mode. */
- psycho_write(strbuf->strbuf_control, control);
-
- for (i = 0; i < 16; i++) {
- int j, saw_error, first, last;
-
- saw_error = 0;
- first = i * 8;
- last = first + 8;
- for (j = first; j < last; j++) {
- unsigned long errval = stc_error_buf[j];
- if (errval != 0) {
- saw_error++;
- printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
- pbm->name,
- j,
- (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
- (errval & PSYCHO_STCERR_READ) ? 1 : 0);
- }
- }
- if (saw_error != 0) {
- unsigned long tagval = stc_tag_buf[i];
- unsigned long lineval = stc_line_buf[i];
- printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
- pbm->name,
- i,
- ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
- (tagval & PSYCHO_STCTAG_VPN),
- ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
- ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
- printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
- "V(%d)FOFN(%d)]\n",
- pbm->name,
- i,
- ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
- ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
- ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
- ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
- ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
- ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
- }
- }
-
- spin_unlock(&stc_buf_lock);
-}
-
-static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
- unsigned long afsr,
- unsigned long afar,
- enum psycho_error_type type)
-{
- __psycho_check_one_stc(pbm,
- (pbm == &pbm->parent->pbm_A));
-}
/* When an Uncorrectable Error or a PCI Error happens, we
* interrogate the IOMMU state to see if it is the cause.
@@ -271,122 +107,7 @@ static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
#define PSYCHO_IOMMU_TSBBASE 0x0208UL
#define PSYCHO_IOMMU_FLUSH 0x0210UL
#define PSYCHO_IOMMU_TAG 0xa580UL
-#define PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
-#define PSYCHO_IOMMU_TAG_ERR (0x1UL << 22UL)
-#define PSYCHO_IOMMU_TAG_WRITE (0x1UL << 21UL)
-#define PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
-#define PSYCHO_IOMMU_TAG_SIZE (0x1UL << 19UL)
-#define PSYCHO_IOMMU_TAG_VPAGE 0x7ffffUL
#define PSYCHO_IOMMU_DATA 0xa600UL
-#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
-#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
-#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
-static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
- unsigned long afsr,
- unsigned long afar,
- enum psycho_error_type type)
-{
- struct iommu *iommu = pbm->iommu;
- unsigned long iommu_tag[16];
- unsigned long iommu_data[16];
- unsigned long flags;
- u64 control;
- int i;
-
- spin_lock_irqsave(&iommu->lock, flags);
- control = psycho_read(iommu->iommu_control);
- if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
- char *type_string;
-
- /* Clear the error encountered bit. */
- control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
- psycho_write(iommu->iommu_control, control);
-
- switch((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
- case 0:
- type_string = "Protection Error";
- break;
- case 1:
- type_string = "Invalid Error";
- break;
- case 2:
- type_string = "TimeOut Error";
- break;
- case 3:
- default:
- type_string = "ECC Error";
- break;
- };
- printk("%s: IOMMU Error, type[%s]\n",
- pbm->name, type_string);
-
- /* Put the IOMMU into diagnostic mode and probe
- * it's TLB for entries with error status.
- *
- * It is very possible for another DVMA to occur
- * while we do this probe, and corrupt the system
- * further. But we are so screwed at this point
- * that we are likely to crash hard anyways, so
- * get as much diagnostic information to the
- * console as we can.
- */
- psycho_write(iommu->iommu_control,
- control | PSYCHO_IOMMU_CTRL_DENAB);
- for (i = 0; i < 16; i++) {
- unsigned long base = pbm->controller_regs;
-
- iommu_tag[i] =
- psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
- iommu_data[i] =
- psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL));
-
- /* Now clear out the entry. */
- psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
- psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
- }
-
- /* Leave diagnostic mode. */
- psycho_write(iommu->iommu_control, control);
-
- for (i = 0; i < 16; i++) {
- unsigned long tag, data;
-
- tag = iommu_tag[i];
- if (!(tag & PSYCHO_IOMMU_TAG_ERR))
- continue;
-
- data = iommu_data[i];
- switch((tag & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
- case 0:
- type_string = "Protection Error";
- break;
- case 1:
- type_string = "Invalid Error";
- break;
- case 2:
- type_string = "TimeOut Error";
- break;
- case 3:
- default:
- type_string = "ECC Error";
- break;
- };
- printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
- pbm->name, i, type_string,
- ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
- ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
- ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
- (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
- printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
- pbm->name, i,
- ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
- ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
- (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
- }
- }
- __psycho_check_stc_error(pbm, afsr, afar, type);
- spin_unlock_irqrestore(&iommu->lock, flags);
-}
/* Uncorrectable Errors. Cause of the error and the address are
* recorded in the UE_AFSR and UE_AFAR of PSYCHO. They are errors
@@ -410,15 +131,14 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
{
struct pci_pbm_info *pbm = dev_id;
- struct pci_controller_info *p = pbm->parent;
unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
unsigned long afsr, afar, error_bits;
int reported;
/* Latch uncorrectable error status. */
- afar = psycho_read(afar_reg);
- afsr = psycho_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear the primary/secondary error status bits. */
error_bits = afsr &
@@ -426,7 +146,7 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR);
if (!error_bits)
return IRQ_NONE;
- psycho_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -463,8 +183,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
printk("]\n");
/* Interrogate both IOMMUs for error status. */
- psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
- psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
+ psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
+ if (pbm->sibling)
+ psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR);
return IRQ_HANDLED;
}
@@ -495,8 +216,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
int reported;
/* Latch error status. */
- afar = psycho_read(afar_reg);
- afsr = psycho_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear primary/secondary error status bits. */
error_bits = afsr &
@@ -504,7 +225,7 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);
if (!error_bits)
return IRQ_NONE;
- psycho_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Correctable Error, primary error type[%s]\n",
@@ -554,164 +275,9 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
*/
#define PSYCHO_PCI_AFSR_A 0x2010UL
#define PSYCHO_PCI_AFSR_B 0x4010UL
-#define PSYCHO_PCIAFSR_PMA 0x8000000000000000UL /* Primary Master Abort Error */
-#define PSYCHO_PCIAFSR_PTA 0x4000000000000000UL /* Primary Target Abort Error */
-#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000UL /* Primary Excessive Retries */
-#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000UL /* Primary Parity Error */
-#define PSYCHO_PCIAFSR_SMA 0x0800000000000000UL /* Secondary Master Abort Error */
-#define PSYCHO_PCIAFSR_STA 0x0400000000000000UL /* Secondary Target Abort Error */
-#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000UL /* Secondary Excessive Retries */
-#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000UL /* Secondary Parity Error */
-#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000UL /* Reserved */
-#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000UL /* Bytemask of failed transfer */
-#define PSYCHO_PCIAFSR_BLK 0x0000000080000000UL /* Trans was block operation */
-#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000UL /* Reserved */
-#define PSYCHO_PCIAFSR_MID 0x000000003e000000UL /* MID causing the error */
-#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffffUL /* Reserved */
#define PSYCHO_PCI_AFAR_A 0x2018UL
#define PSYCHO_PCI_AFAR_B 0x4018UL
-static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a)
-{
- unsigned long csr_reg, csr, csr_error_bits;
- irqreturn_t ret = IRQ_NONE;
- u16 stat, *addr;
-
- if (is_pbm_a) {
- csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
- } else {
- csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL;
- }
- csr = psycho_read(csr_reg);
- csr_error_bits =
- csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
- if (csr_error_bits) {
- /* Clear the errors. */
- psycho_write(csr_reg, csr);
-
- /* Log 'em. */
- if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
- printk("%s: PCI streaming byte hole error asserted.\n",
- pbm->name);
- if (csr_error_bits & PSYCHO_PCICTRL_SERR)
- printk("%s: PCI SERR signal asserted.\n", pbm->name);
- ret = IRQ_HANDLED;
- }
- addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
- 0, PCI_STATUS);
- pci_config_read16(addr, &stat);
- if (stat & (PCI_STATUS_PARITY |
- PCI_STATUS_SIG_TARGET_ABORT |
- PCI_STATUS_REC_TARGET_ABORT |
- PCI_STATUS_REC_MASTER_ABORT |
- PCI_STATUS_SIG_SYSTEM_ERROR)) {
- printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
- pbm->name, stat);
- pci_config_write16(addr, 0xffff);
- ret = IRQ_HANDLED;
- }
- return ret;
-}
-
-static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
-{
- struct pci_pbm_info *pbm = dev_id;
- struct pci_controller_info *p = pbm->parent;
- unsigned long afsr_reg, afar_reg;
- unsigned long afsr, afar, error_bits;
- int is_pbm_a, reported;
-
- is_pbm_a = (pbm == &pbm->parent->pbm_A);
- if (is_pbm_a) {
- afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A;
- afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A;
- } else {
- afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B;
- afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B;
- }
-
- /* Latch error status. */
- afar = psycho_read(afar_reg);
- afsr = psycho_read(afsr_reg);
-
- /* Clear primary/secondary error status bits. */
- error_bits = afsr &
- (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
- PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
- PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
- PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
- if (!error_bits)
- return psycho_pcierr_intr_other(pbm, is_pbm_a);
- psycho_write(afsr_reg, error_bits);
-
- /* Log the error. */
- printk("%s: PCI Error, primary error type[%s]\n",
- pbm->name,
- (((error_bits & PSYCHO_PCIAFSR_PMA) ?
- "Master Abort" :
- ((error_bits & PSYCHO_PCIAFSR_PTA) ?
- "Target Abort" :
- ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
- "Excessive Retries" :
- ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
- "Parity Error" : "???"))))));
- printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
- pbm->name,
- (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
- (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
- (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
- printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
- printk("%s: PCI Secondary errors [", pbm->name);
- reported = 0;
- if (afsr & PSYCHO_PCIAFSR_SMA) {
- reported++;
- printk("(Master Abort)");
- }
- if (afsr & PSYCHO_PCIAFSR_STA) {
- reported++;
- printk("(Target Abort)");
- }
- if (afsr & PSYCHO_PCIAFSR_SRTRY) {
- reported++;
- printk("(Excessive Retries)");
- }
- if (afsr & PSYCHO_PCIAFSR_SPERR) {
- reported++;
- printk("(Parity Error)");
- }
- if (!reported)
- printk("(none)");
- printk("]\n");
-
- /* For the error types shown, scan PBM's PCI bus for devices
- * which have logged that error type.
- */
-
- /* If we see a Target Abort, this could be the result of an
- * IOMMU translation error of some sort. It is extremely
- * useful to log this information as usually it indicates
- * a bug in the IOMMU support code or a PCI device driver.
- */
- if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
- psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
- pci_scan_for_target_abort(pbm, pbm->pci_bus);
- }
- if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
- pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
- /* For excessive retries, PSYCHO/PBM will abort the device
- * and there is no way to specifically check for excessive
- * retries in the config space status registers. So what
- * we hope is that we'll catch it via the master/target
- * abort events.
- */
-
- if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
- pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
- return IRQ_HANDLED;
-}
-
/* XXX What about PowerFail/PowerManagement??? -DaveM */
#define PSYCHO_ECC_CTRL 0x0020
#define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */
@@ -719,7 +285,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
#define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */
static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->prom_node);
+ struct of_device *op = of_find_device_by_node(pbm->op->node);
unsigned long base = pbm->controller_regs;
u64 tmp;
int err;
@@ -762,27 +328,26 @@ static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
"err=%d\n", pbm->name, err);
/* Enable UE and CE interrupts for controller. */
- psycho_write(base + PSYCHO_ECC_CTRL,
- (PSYCHO_ECCCTRL_EE |
- PSYCHO_ECCCTRL_UE |
- PSYCHO_ECCCTRL_CE));
+ upa_writeq((PSYCHO_ECCCTRL_EE |
+ PSYCHO_ECCCTRL_UE |
+ PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL);
/* Enable PCI Error interrupts and clear error
* bits for each PBM.
*/
- tmp = psycho_read(base + PSYCHO_PCIA_CTRL);
+ tmp = upa_readq(base + PSYCHO_PCIA_CTRL);
tmp |= (PSYCHO_PCICTRL_SERR |
PSYCHO_PCICTRL_SBH_ERR |
PSYCHO_PCICTRL_EEN);
tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
- psycho_write(base + PSYCHO_PCIA_CTRL, tmp);
+ upa_writeq(tmp, base + PSYCHO_PCIA_CTRL);
- tmp = psycho_read(base + PSYCHO_PCIB_CTRL);
+ tmp = upa_readq(base + PSYCHO_PCIB_CTRL);
tmp |= (PSYCHO_PCICTRL_SERR |
PSYCHO_PCICTRL_SBH_ERR |
PSYCHO_PCICTRL_EEN);
tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
- psycho_write(base + PSYCHO_PCIB_CTRL, tmp);
+ upa_writeq(tmp, base + PSYCHO_PCIB_CTRL);
}
/* PSYCHO boot time probing and initialization. */
@@ -803,11 +368,12 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}
-static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
+static void __init psycho_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
pbm_config_busmastering(pbm);
pbm->is_66mhz_capable = 0;
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
/* After the PCI bus scan is complete, we can register
* the error interrupt handlers.
@@ -815,61 +381,6 @@ static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
psycho_register_error_handlers(pbm);
}
-static int psycho_iommu_init(struct pci_pbm_info *pbm)
-{
- struct iommu *iommu = pbm->iommu;
- unsigned long i;
- u64 control;
- int err;
-
- /* Register addresses. */
- iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
- iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
- iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
- iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-
- /* PSYCHO's IOMMU lacks ctx flushing. */
- iommu->iommu_ctxflush = 0;
-
- /* We use the main control register of PSYCHO as the write
- * completion register.
- */
- iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
-
- /*
- * Invalidate TLB Entries.
- */
- control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
- control |= PSYCHO_IOMMU_CTRL_DENAB;
- psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
- for(i = 0; i < 16; i++) {
- psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
- psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
- }
-
- /* Leave diag mode enabled for full-flushing done
- * in pci_iommu.c
- */
- err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff,
- pbm->numa_node);
- if (err)
- return err;
-
- psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
- __pa(iommu->page_table));
-
- control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
- control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
- control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
- psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-
- /* If necessary, hook us up for starfire IRQ translations. */
- if (this_is_starfire)
- starfire_hookup(pbm->portid);
-
- return 0;
-}
-
#define PSYCHO_IRQ_RETRY 0x1a00UL
#define PSYCHO_PCIA_DIAG 0x2020UL
#define PSYCHO_PCIB_DIAG 0x4020UL
@@ -886,28 +397,28 @@ static void psycho_controller_hwinit(struct pci_pbm_info *pbm)
{
u64 tmp;
- psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
+ upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY);
/* Enable arbiter for all PCI slots. */
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL);
tmp |= PSYCHO_PCICTRL_AEN;
- psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL);
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL);
tmp |= PSYCHO_PCICTRL_AEN;
- psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL);
/* Disable DMA write / PIO read synchronization on
* both PCI bus segments.
* [ U2P Erratum 1243770, STP2223BGA data sheet ]
*/
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG);
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG);
- tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
+ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG);
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
+ upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG);
}
static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
@@ -920,10 +431,16 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A;
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A;
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A;
+ pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A;
+ pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A;
+ pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A;
} else {
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B;
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B;
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B;
+ pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B;
+ pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B;
+ pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B;
}
/* PSYCHO's streaming buffer lacks ctx flushing. */
pbm->stc.strbuf_ctxflush = 0;
@@ -946,7 +463,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
*/
#undef PSYCHO_STRBUF_RERUN_ENABLE
#undef PSYCHO_STRBUF_RERUN_DISABLE
- control = psycho_read(pbm->stc.strbuf_control);
+ control = upa_readq(pbm->stc.strbuf_control);
control |= PSYCHO_STRBUF_CTRL_ENAB;
control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR);
#ifdef PSYCHO_STRBUF_RERUN_ENABLE
@@ -956,7 +473,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
control |= PSYCHO_STRBUF_CTRL_RRDIS;
#endif
#endif
- psycho_write(pbm->stc.strbuf_control, control);
+ upa_writeq(control, pbm->stc.strbuf_control);
pbm->stc.strbuf_enabled = 1;
}
@@ -968,111 +485,134 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
#define PSYCHO_MEMSPACE_B 0x180000000UL
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
-static void __init psycho_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, int is_pbm_a)
+static void __init psycho_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, int is_pbm_a)
{
- struct property *prop;
- struct pci_pbm_info *pbm;
-
- if (is_pbm_a)
- pbm = &p->pbm_A;
- else
- pbm = &p->pbm_B;
-
- pbm->next = pci_pbm_root;
- pci_pbm_root = pbm;
-
- pbm->numa_node = -1;
-
- pbm->scan_bus = psycho_scan_bus;
- pbm->pci_ops = &sun4u_pci_ops;
- pbm->config_space_reg_bits = 8;
-
- pbm->index = pci_num_pbms++;
-
- pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
- pbm->chip_version = 0;
- prop = of_find_property(dp, "version#", NULL);
- if (prop)
- pbm->chip_version = *(int *) prop->value;
- pbm->chip_revision = 0;
- prop = of_find_property(dp, "module-revision#", NULL);
- if (prop)
- pbm->chip_revision = *(int *) prop->value;
-
- pbm->parent = p;
- pbm->prom_node = dp;
- pbm->name = dp->full_name;
-
- printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
- pbm->name,
- pbm->chip_version, pbm->chip_revision);
-
- pci_determine_mem_io_space(pbm);
+ psycho_pbm_init_common(pbm, op, "PSYCHO", PBM_CHIP_TYPE_PSYCHO);
+ psycho_pbm_strbuf_init(pbm, is_pbm_a);
+ psycho_scan_bus(pbm, &op->dev);
+}
- pci_get_pbm_props(pbm);
+static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
+{
+ struct pci_pbm_info *pbm;
- psycho_pbm_strbuf_init(pbm, is_pbm_a);
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+ if (pbm->portid == upa_portid)
+ return pbm;
+ }
+ return NULL;
}
#define PSYCHO_CONFIGSPACE 0x001000000UL
-void __init psycho_init(struct device_node *dp, char *model_name)
+static int __devinit psycho_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_prom64_registers *pr_regs;
- struct pci_controller_info *p;
+ const struct linux_prom64_registers *pr_regs;
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
struct iommu *iommu;
- struct property *prop;
+ int is_pbm_a, err;
u32 upa_portid;
- int is_pbm_a;
- upa_portid = 0xff;
- prop = of_find_property(dp, "upa-portid", NULL);
- if (prop)
- upa_portid = *(u32 *) prop->value;
+ upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
- for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
- struct pci_controller_info *p = pbm->parent;
+ err = -ENOMEM;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+ goto out_err;
+ }
- if (p->pbm_A.portid == upa_portid) {
- is_pbm_a = (p->pbm_A.prom_node == NULL);
- psycho_pbm_init(p, dp, is_pbm_a);
- return;
+ pbm->sibling = psycho_find_sibling(upa_portid);
+ if (pbm->sibling) {
+ iommu = pbm->sibling->iommu;
+ } else {
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+ goto out_free_controller;
}
}
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ pbm->iommu = iommu;
+ pbm->portid = upa_portid;
- p->pbm_A.iommu = p->pbm_B.iommu = iommu;
+ pr_regs = of_get_property(dp, "reg", NULL);
+ err = -ENODEV;
+ if (!pr_regs) {
+ printk(KERN_ERR PFX "No reg property.\n");
+ goto out_free_iommu;
+ }
- p->pbm_A.portid = upa_portid;
- p->pbm_B.portid = upa_portid;
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
- prop = of_find_property(dp, "reg", NULL);
- pr_regs = prop->value;
+ pbm->controller_regs = pr_regs[2].phys_addr;
+ pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
- p->pbm_A.controller_regs = pr_regs[2].phys_addr;
- p->pbm_B.controller_regs = pr_regs[2].phys_addr;
+ if (is_pbm_a) {
+ pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A;
+ pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A;
+ pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIA_CTRL;
+ } else {
+ pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B;
+ pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B;
+ pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIB_CTRL;
+ }
- p->pbm_A.config_space = p->pbm_B.config_space =
- (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
+ psycho_controller_hwinit(pbm);
+ if (!pbm->sibling) {
+ err = psycho_iommu_init(pbm, 128, 0xc0000000,
+ 0xffffffff, PSYCHO_CONTROL);
+ if (err)
+ goto out_free_iommu;
- psycho_controller_hwinit(&p->pbm_A);
+ /* If necessary, hook us up for starfire IRQ translations. */
+ if (this_is_starfire)
+ starfire_hookup(pbm->portid);
+ }
- if (psycho_iommu_init(&p->pbm_A))
- goto fatal_memory_error;
+ psycho_pbm_init(pbm, op, is_pbm_a);
- is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
- psycho_pbm_init(p, dp, is_pbm_a);
- return;
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ if (pbm->sibling)
+ pbm->sibling->sibling = pbm;
+
+ dev_set_drvdata(&op->dev, pbm);
+
+ return 0;
+
+out_free_iommu:
+ if (!pbm->sibling)
+ kfree(pbm->iommu);
-fatal_memory_error:
- prom_printf("PSYCHO: Fatal memory allocation error.\n");
- prom_halt();
+out_free_controller:
+ kfree(pbm);
+
+out_err:
+ return err;
}
+
+static struct of_device_id __initdata psycho_match[] = {
+ {
+ .name = "pci",
+ .compatible = "pci108e,8000",
+ },
+ {},
+};
+
+static struct of_platform_driver psycho_driver = {
+ .name = DRIVER_NAME,
+ .match_table = psycho_match,
+ .probe = psycho_probe,
+};
+
+static int __init psycho_init(void)
+{
+ return of_register_driver(&psycho_driver, &of_bus_type);
+}
+
+subsys_initcall(psycho_init);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index ade5184e75d..713257b6963 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -16,31 +16,15 @@
#include <asm/apb.h>
#include <asm/iommu.h>
#include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/oplib.h>
#include <asm/prom.h>
+#include <asm/upa.h>
#include "pci_impl.h"
#include "iommu_common.h"
+#include "psycho_common.h"
-/* All SABRE registers are 64-bits. The following accessor
- * routines are how they are accessed. The REG parameter
- * is a physical address.
- */
-#define sabre_read(__reg) \
-({ u64 __ret; \
- __asm__ __volatile__("ldxa [%1] %2, %0" \
- : "=r" (__ret) \
- : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory"); \
- __ret; \
-})
-#define sabre_write(__reg, __val) \
- __asm__ __volatile__("stxa %0, [%1] %2" \
- : /* no outputs */ \
- : "r" (__val), "r" (__reg), \
- "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory")
+#define DRIVER_NAME "sabre"
+#define PFX DRIVER_NAME ": "
/* SABRE PCI controller register offsets and definitions. */
#define SABRE_UE_AFSR 0x0030UL
@@ -208,95 +192,6 @@
static int hummingbird_p;
static struct pci_bus *sabre_root_bus;
-/* SABRE error handling support. */
-static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
- unsigned long afsr,
- unsigned long afar)
-{
- struct iommu *iommu = pbm->iommu;
- unsigned long iommu_tag[16];
- unsigned long iommu_data[16];
- unsigned long flags;
- u64 control;
- int i;
-
- spin_lock_irqsave(&iommu->lock, flags);
- control = sabre_read(iommu->iommu_control);
- if (control & SABRE_IOMMUCTRL_ERR) {
- char *type_string;
-
- /* Clear the error encountered bit.
- * NOTE: On Sabre this is write 1 to clear,
- * which is different from Psycho.
- */
- sabre_write(iommu->iommu_control, control);
- switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) {
- case 1:
- type_string = "Invalid Error";
- break;
- case 3:
- type_string = "ECC Error";
- break;
- default:
- type_string = "Unknown";
- break;
- };
- printk("%s: IOMMU Error, type[%s]\n",
- pbm->name, type_string);
-
- /* Enter diagnostic mode and probe for error'd
- * entries in the IOTLB.
- */
- control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR);
- sabre_write(iommu->iommu_control,
- (control | SABRE_IOMMUCTRL_DENAB));
- for (i = 0; i < 16; i++) {
- unsigned long base = pbm->controller_regs;
-
- iommu_tag[i] =
- sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
- iommu_data[i] =
- sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL));
- sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0);
- sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0);
- }
- sabre_write(iommu->iommu_control, control);
-
- for (i = 0; i < 16; i++) {
- unsigned long tag, data;
-
- tag = iommu_tag[i];
- if (!(tag & SABRE_IOMMUTAG_ERR))
- continue;
-
- data = iommu_data[i];
- switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) {
- case 1:
- type_string = "Invalid Error";
- break;
- case 3:
- type_string = "ECC Error";
- break;
- default:
- type_string = "Unknown";
- break;
- };
- printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
- pbm->name, i, tag, type_string,
- ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
- ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
- ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
- printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
- pbm->name, i, data,
- ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
- ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
- ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
- ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT));
- }
- }
- spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
{
struct pci_pbm_info *pbm = dev_id;
@@ -306,8 +201,8 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
int reported;
/* Latch uncorrectable error status. */
- afar = sabre_read(afar_reg);
- afsr = sabre_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear the primary/secondary error status bits. */
error_bits = afsr &
@@ -316,7 +211,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);
if (!error_bits)
return IRQ_NONE;
- sabre_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
@@ -352,7 +247,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
printk("]\n");
/* Interrogate IOMMU for error status. */
- sabre_check_iommu_error(pbm, afsr, afar);
+ psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
return IRQ_HANDLED;
}
@@ -366,8 +261,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
int reported;
/* Latch error status. */
- afar = sabre_read(afar_reg);
- afsr = sabre_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear primary/secondary error status bits. */
error_bits = afsr &
@@ -375,7 +270,7 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);
if (!error_bits)
return IRQ_NONE;
- sabre_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Correctable Error, primary error type[%s]\n",
@@ -413,136 +308,9 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm)
-{
- unsigned long csr_reg, csr, csr_error_bits;
- irqreturn_t ret = IRQ_NONE;
- u16 stat;
-
- csr_reg = pbm->controller_regs + SABRE_PCICTRL;
- csr = sabre_read(csr_reg);
- csr_error_bits =
- csr & SABRE_PCICTRL_SERR;
- if (csr_error_bits) {
- /* Clear the errors. */
- sabre_write(csr_reg, csr);
-
- /* Log 'em. */
- if (csr_error_bits & SABRE_PCICTRL_SERR)
- printk("%s: PCI SERR signal asserted.\n",
- pbm->name);
- ret = IRQ_HANDLED;
- }
- pci_bus_read_config_word(sabre_root_bus, 0,
- PCI_STATUS, &stat);
- if (stat & (PCI_STATUS_PARITY |
- PCI_STATUS_SIG_TARGET_ABORT |
- PCI_STATUS_REC_TARGET_ABORT |
- PCI_STATUS_REC_MASTER_ABORT |
- PCI_STATUS_SIG_SYSTEM_ERROR)) {
- printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
- pbm->name, stat);
- pci_bus_write_config_word(sabre_root_bus, 0,
- PCI_STATUS, 0xffff);
- ret = IRQ_HANDLED;
- }
- return ret;
-}
-
-static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
-{
- struct pci_pbm_info *pbm = dev_id;
- unsigned long afsr_reg, afar_reg;
- unsigned long afsr, afar, error_bits;
- int reported;
-
- afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
- afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
-
- /* Latch error status. */
- afar = sabre_read(afar_reg);
- afsr = sabre_read(afsr_reg);
-
- /* Clear primary/secondary error status bits. */
- error_bits = afsr &
- (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA |
- SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR |
- SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
- SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
- if (!error_bits)
- return sabre_pcierr_intr_other(pbm);
- sabre_write(afsr_reg, error_bits);
-
- /* Log the error. */
- printk("%s: PCI Error, primary error type[%s]\n",
- pbm->name,
- (((error_bits & SABRE_PIOAFSR_PMA) ?
- "Master Abort" :
- ((error_bits & SABRE_PIOAFSR_PTA) ?
- "Target Abort" :
- ((error_bits & SABRE_PIOAFSR_PRTRY) ?
- "Excessive Retries" :
- ((error_bits & SABRE_PIOAFSR_PPERR) ?
- "Parity Error" : "???"))))));
- printk("%s: bytemask[%04lx] was_block(%d)\n",
- pbm->name,
- (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
- (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
- printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
- printk("%s: PCI Secondary errors [", pbm->name);
- reported = 0;
- if (afsr & SABRE_PIOAFSR_SMA) {
- reported++;
- printk("(Master Abort)");
- }
- if (afsr & SABRE_PIOAFSR_STA) {
- reported++;
- printk("(Target Abort)");
- }
- if (afsr & SABRE_PIOAFSR_SRTRY) {
- reported++;
- printk("(Excessive Retries)");
- }
- if (afsr & SABRE_PIOAFSR_SPERR) {
- reported++;
- printk("(Parity Error)");
- }
- if (!reported)
- printk("(none)");
- printk("]\n");
-
- /* For the error types shown, scan both PCI buses for devices
- * which have logged that error type.
- */
-
- /* If we see a Target Abort, this could be the result of an
- * IOMMU translation error of some sort. It is extremely
- * useful to log this information as usually it indicates
- * a bug in the IOMMU support code or a PCI device driver.
- */
- if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
- sabre_check_iommu_error(pbm, afsr, afar);
- pci_scan_for_target_abort(pbm, pbm->pci_bus);
- }
- if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
- pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
- /* For excessive retries, SABRE/PBM will abort the device
- * and there is no way to specifically check for excessive
- * retries in the config space status registers. So what
- * we hope is that we'll catch it via the master/target
- * abort events.
- */
-
- if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
- pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
- return IRQ_HANDLED;
-}
-
static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct device_node *dp = pbm->prom_node;
+ struct device_node *dp = pbm->op->node;
struct of_device *op;
unsigned long base = pbm->controller_regs;
u64 tmp;
@@ -568,33 +336,34 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
* registering the handler so that we don't get spurious
* interrupts.
*/
- sabre_write(base + SABRE_UE_AFSR,
- (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
- SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
- SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
+ upa_writeq((SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
+ SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
+ SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE),
+ base + SABRE_UE_AFSR);
err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
if (err)
printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
pbm->name, err);
- sabre_write(base + SABRE_CE_AFSR,
- (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
- SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
+ upa_writeq((SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
+ SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR),
+ base + SABRE_CE_AFSR);
+
err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
if (err)
printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
pbm->name, err);
- err = request_irq(op->irqs[0], sabre_pcierr_intr, 0,
+ err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
"SABRE_PCIERR", pbm);
if (err)
printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
pbm->name, err);
- tmp = sabre_read(base + SABRE_PCICTRL);
+ tmp = upa_readq(base + SABRE_PCICTRL);
tmp |= SABRE_PCICTRL_ERREN;
- sabre_write(base + SABRE_PCICTRL, tmp);
+ upa_writeq(tmp, base + SABRE_PCICTRL);
}
static void apb_init(struct pci_bus *sabre_bus)
@@ -633,7 +402,8 @@ static void apb_init(struct pci_bus *sabre_bus)
}
}
-static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
+static void __init sabre_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
static int once;
@@ -656,12 +426,12 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
* to live at bus 0.
*/
if (once != 0) {
- prom_printf("SABRE: Multiple controllers unsupported.\n");
- prom_halt();
+ printk(KERN_ERR PFX "Multiple controllers unsupported.\n");
+ return;
}
once++;
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
if (!pbm->pci_bus)
return;
@@ -672,133 +442,58 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
sabre_register_error_handlers(pbm);
}
-static int sabre_iommu_init(struct pci_pbm_info *pbm,
- int tsbsize, unsigned long dvma_offset,
- u32 dma_mask)
-{
- struct iommu *iommu = pbm->iommu;
- unsigned long i;
- u64 control;
- int err;
-
- /* Register addresses. */
- iommu->iommu_control = pbm->controller_regs + SABRE_IOMMU_CONTROL;
- iommu->iommu_tsbbase = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
- iommu->iommu_flush = pbm->controller_regs + SABRE_IOMMU_FLUSH;
- iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
- iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
- /* Sabre's IOMMU lacks ctx flushing. */
- iommu->iommu_ctxflush = 0;
-
- /* Invalidate TLB Entries. */
- control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
- control |= SABRE_IOMMUCTRL_DENAB;
- sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
- for(i = 0; i < 16; i++) {
- sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
- sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
- }
-
- /* Leave diag mode enabled for full-flushing done
- * in pci_iommu.c
- */
- err = iommu_table_init(iommu, tsbsize * 1024 * 8,
- dvma_offset, dma_mask, pbm->numa_node);
- if (err)
- return err;
-
- sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
- __pa(iommu->page_table));
-
- control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
- control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
- control |= SABRE_IOMMUCTRL_ENAB;
- switch(tsbsize) {
- case 64:
- control |= SABRE_IOMMU_TSBSZ_64K;
- break;
- case 128:
- control |= SABRE_IOMMU_TSBSZ_128K;
- break;
- default:
- prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
- prom_halt();
- break;
- }
- sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
- return 0;
-}
-
-static void __init sabre_pbm_init(struct pci_controller_info *p,
- struct pci_pbm_info *pbm, struct device_node *dp)
+static void __init sabre_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op)
{
- pbm->name = dp->full_name;
- printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
- pbm->numa_node = -1;
-
- pbm->scan_bus = sabre_scan_bus;
- pbm->pci_ops = &sun4u_pci_ops;
- pbm->config_space_reg_bits = 8;
-
- pbm->index = pci_num_pbms++;
-
- pbm->chip_type = PBM_CHIP_TYPE_SABRE;
- pbm->parent = p;
- pbm->prom_node = dp;
- pci_get_pbm_props(pbm);
-
- pci_determine_mem_io_space(pbm);
+ psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE);
+ pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR;
+ pbm->pci_afar = pbm->controller_regs + SABRE_PIOAFAR;
+ pbm->pci_csr = pbm->controller_regs + SABRE_PCICTRL;
+ sabre_scan_bus(pbm, &op->dev);
}
-void __init sabre_init(struct device_node *dp, char *model_name)
+static int __devinit sabre_probe(struct of_device *op,
+ const struct of_device_id *match)
{
const struct linux_prom64_registers *pr_regs;
- struct pci_controller_info *p;
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
+ u32 upa_portid, dma_mask;
struct iommu *iommu;
- int tsbsize;
+ int tsbsize, err;
const u32 *vdma;
- u32 upa_portid, dma_mask;
u64 clear_irq;
- hummingbird_p = 0;
- if (!strcmp(model_name, "pci108e,a001"))
- hummingbird_p = 1;
- else if (!strcmp(model_name, "SUNW,sabre")) {
- const char *compat = of_get_property(dp, "compatible", NULL);
- if (compat && !strcmp(compat, "pci108e,a001"))
- hummingbird_p = 1;
- if (!hummingbird_p) {
- struct device_node *dp;
-
- /* Of course, Sun has to encode things a thousand
- * different ways, inconsistently.
- */
- for_each_node_by_type(dp, "cpu") {
- if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
- hummingbird_p = 1;
- }
+ hummingbird_p = (match->data != NULL);
+ if (!hummingbird_p) {
+ struct device_node *cpu_dp;
+
+ /* Of course, Sun has to encode things a thousand
+ * different ways, inconsistently.
+ */
+ for_each_node_by_type(cpu_dp, "cpu") {
+ if (!strcmp(cpu_dp->name, "SUNW,UltraSPARC-IIe"))
+ hummingbird_p = 1;
}
}
- p = kzalloc(sizeof(*p), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ err = -ENOMEM;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+ goto out_err;
+ }
+
+ iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+ goto out_free_controller;
+ }
- iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
- pbm = &p->pbm_A;
pbm->iommu = iommu;
upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
- pbm->next = pci_pbm_root;
- pci_pbm_root = pbm;
-
pbm->portid = upa_portid;
/*
@@ -806,6 +501,11 @@ void __init sabre_init(struct device_node *dp, char *model_name)
*/
pr_regs = of_get_property(dp, "reg", NULL);
+ err = -ENODEV;
+ if (!pr_regs) {
+ printk(KERN_ERR PFX "No reg property\n");
+ goto out_free_iommu;
+ }
/*
* First REG in property is base of entire SABRE register space.
@@ -816,22 +516,25 @@ void __init sabre_init(struct device_node *dp, char *model_name)
/* PCI first */
for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
- sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+ upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
/* Then OBIO */
for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
- sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+ upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
/* Error interrupts are enabled later after the bus scan. */
- sabre_write(pbm->controller_regs + SABRE_PCICTRL,
- (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR |
- SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
+ upa_writeq((SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR |
+ SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN),
+ pbm->controller_regs + SABRE_PCICTRL);
/* Now map in PCI config space for entire SABRE. */
- pbm->config_space =
- (pbm->controller_regs + SABRE_CONFIGSPACE);
+ pbm->config_space = pbm->controller_regs + SABRE_CONFIGSPACE;
vdma = of_get_property(dp, "virtual-dma", NULL);
+ if (!vdma) {
+ printk(KERN_ERR PFX "No virtual-dma property\n");
+ goto out_free_iommu;
+ }
dma_mask = vdma[0];
switch(vdma[1]) {
@@ -849,20 +552,58 @@ void __init sabre_init(struct device_node *dp, char *model_name)
tsbsize = 128;
break;
default:
- prom_printf("SABRE: strange virtual-dma size.\n");
- prom_halt();
+ printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+ goto out_free_iommu;
}
- if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask))
- goto fatal_memory_error;
+ err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC);
+ if (err)
+ goto out_free_iommu;
/*
* Look for APB underneath.
*/
- sabre_pbm_init(p, pbm, dp);
- return;
+ sabre_pbm_init(pbm, op);
-fatal_memory_error:
- prom_printf("SABRE: Fatal memory allocation error.\n");
- prom_halt();
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ dev_set_drvdata(&op->dev, pbm);
+
+ return 0;
+
+out_free_iommu:
+ kfree(pbm->iommu);
+
+out_free_controller:
+ kfree(pbm);
+
+out_err:
+ return err;
+}
+
+static struct of_device_id __initdata sabre_match[] = {
+ {
+ .name = "pci",
+ .compatible = "pci108e,a001",
+ .data = (void *) 1,
+ },
+ {
+ .name = "pci",
+ .compatible = "pci108e,a000",
+ },
+ {},
+};
+
+static struct of_platform_driver sabre_driver = {
+ .name = DRIVER_NAME,
+ .match_table = sabre_match,
+ .probe = sabre_probe,
+};
+
+static int __init sabre_init(void)
+{
+ return of_register_driver(&sabre_driver, &of_bus_type);
}
+
+subsys_initcall(sabre_init);
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 9248c6737f0..45d9dba1ba1 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,6 +1,6 @@
/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
*
- * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -13,32 +13,15 @@
#include <asm/iommu.h>
#include <asm/irq.h>
-#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
#include "pci_impl.h"
#include "iommu_common.h"
-/* All SCHIZO registers are 64-bits. The following accessor
- * routines are how they are accessed. The REG parameter
- * is a physical address.
- */
-#define schizo_read(__reg) \
-({ u64 __ret; \
- __asm__ __volatile__("ldxa [%1] %2, %0" \
- : "=r" (__ret) \
- : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory"); \
- __ret; \
-})
-#define schizo_write(__reg, __val) \
- __asm__ __volatile__("stxa %0, [%1] %2" \
- : /* no outputs */ \
- : "r" (__val), "r" (__reg), \
- "i" (ASI_PHYS_BYPASS_EC_E) \
- : "memory")
+#define DRIVER_NAME "schizo"
+#define PFX DRIVER_NAME ": "
/* This is a convention that at least Excalibur and Merlin
* follow. I suppose the SCHIZO used in Starcat and friends
@@ -163,25 +146,25 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
* invalidating it before it has a chance to reach
* main memory.
*/
- control = schizo_read(strbuf->strbuf_control);
- schizo_write(strbuf->strbuf_control,
- (control | SCHIZO_STRBUF_CTRL_DENAB));
+ control = upa_readq(strbuf->strbuf_control);
+ upa_writeq((control | SCHIZO_STRBUF_CTRL_DENAB),
+ strbuf->strbuf_control);
for (i = 0; i < 128; i++) {
unsigned long val;
- val = schizo_read(err_base + (i * 8UL));
- schizo_write(err_base + (i * 8UL), 0UL);
+ val = upa_readq(err_base + (i * 8UL));
+ upa_writeq(0UL, err_base + (i * 8UL));
stc_error_buf[i] = val;
}
for (i = 0; i < 16; i++) {
- stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL));
- stc_line_buf[i] = schizo_read(line_base + (i * 8UL));
- schizo_write(tag_base + (i * 8UL), 0UL);
- schizo_write(line_base + (i * 8UL), 0UL);
+ stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+ stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+ upa_writeq(0UL, tag_base + (i * 8UL));
+ upa_writeq(0UL, line_base + (i * 8UL));
}
/* OK, state is logged, exit diagnostic mode. */
- schizo_write(strbuf->strbuf_control, control);
+ upa_writeq(control, strbuf->strbuf_control);
for (i = 0; i < 16; i++) {
int j, saw_error, first, last;
@@ -258,14 +241,14 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
int i;
spin_lock_irqsave(&iommu->lock, flags);
- control = schizo_read(iommu->iommu_control);
+ control = upa_readq(iommu->iommu_control);
if (control & SCHIZO_IOMMU_CTRL_XLTEERR) {
unsigned long base;
char *type_string;
/* Clear the error encountered bit. */
control &= ~SCHIZO_IOMMU_CTRL_XLTEERR;
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
case 0:
@@ -295,24 +278,24 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
* get as much diagnostic information to the
* console as we can.
*/
- schizo_write(iommu->iommu_control,
- control | SCHIZO_IOMMU_CTRL_DENAB);
+ upa_writeq(control | SCHIZO_IOMMU_CTRL_DENAB,
+ iommu->iommu_control);
base = pbm->pbm_regs;
for (i = 0; i < 16; i++) {
iommu_tag[i] =
- schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+ upa_readq(base + SCHIZO_IOMMU_TAG + (i * 8UL));
iommu_data[i] =
- schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+ upa_readq(base + SCHIZO_IOMMU_DATA + (i * 8UL));
/* Now clear out the entry. */
- schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
- schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+ upa_writeq(0, base + SCHIZO_IOMMU_TAG + (i * 8UL));
+ upa_writeq(0, base + SCHIZO_IOMMU_DATA + (i * 8UL));
}
/* Leave diagnostic mode. */
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
for (i = 0; i < 16; i++) {
unsigned long tag, data;
@@ -357,11 +340,12 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
spin_unlock_irqrestore(&iommu->lock, flags);
}
-static void schizo_check_iommu_error(struct pci_controller_info *p,
+static void schizo_check_iommu_error(struct pci_pbm_info *pbm,
enum schizo_error_type type)
{
- schizo_check_iommu_error_pbm(&p->pbm_A, type);
- schizo_check_iommu_error_pbm(&p->pbm_B, type);
+ schizo_check_iommu_error_pbm(pbm, type);
+ if (pbm->sibling)
+ schizo_check_iommu_error_pbm(pbm->sibling, type);
}
/* Uncorrectable ECC error status gathering. */
@@ -386,14 +370,13 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
{
struct pci_pbm_info *pbm = dev_id;
- struct pci_controller_info *p = pbm->parent;
unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
unsigned long afsr, afar, error_bits;
int reported, limit;
/* Latch uncorrectable error status. */
- afar = schizo_read(afar_reg);
+ afar = upa_readq(afar_reg);
/* If either of the error pending bits are set in the
* AFSR, the error status is being actively updated by
@@ -401,7 +384,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
*/
limit = 1000;
do {
- afsr = schizo_read(afsr_reg);
+ afsr = upa_readq(afsr_reg);
} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
/* Clear the primary/secondary error status bits. */
@@ -410,7 +393,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
if (!error_bits)
return IRQ_NONE;
- schizo_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -449,7 +432,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
printk("]\n");
/* Interrogate IOMMU for error status. */
- schizo_check_iommu_error(p, UE_ERR);
+ schizo_check_iommu_error(pbm, UE_ERR);
return IRQ_HANDLED;
}
@@ -481,7 +464,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
int reported, limit;
/* Latch error status. */
- afar = schizo_read(afar_reg);
+ afar = upa_readq(afar_reg);
/* If either of the error pending bits are set in the
* AFSR, the error status is being actively updated by
@@ -489,7 +472,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
*/
limit = 1000;
do {
- afsr = schizo_read(afsr_reg);
+ afsr = upa_readq(afsr_reg);
} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
/* Clear primary/secondary error status bits. */
@@ -498,7 +481,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
if (!error_bits)
return IRQ_NONE;
- schizo_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: Correctable Error, primary error type[%s]\n",
@@ -600,7 +583,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
u16 stat;
csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL;
- csr = schizo_read(csr_reg);
+ csr = upa_readq(csr_reg);
csr_error_bits =
csr & (SCHIZO_PCICTRL_BUS_UNUS |
SCHIZO_PCICTRL_TTO_ERR |
@@ -610,7 +593,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
SCHIZO_PCICTRL_SERR);
if (csr_error_bits) {
/* Clear the errors. */
- schizo_write(csr_reg, csr);
+ upa_writeq(csr, csr_reg);
/* Log 'em. */
if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS)
@@ -650,7 +633,6 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
{
struct pci_pbm_info *pbm = dev_id;
- struct pci_controller_info *p = pbm->parent;
unsigned long afsr_reg, afar_reg, base;
unsigned long afsr, afar, error_bits;
int reported;
@@ -661,8 +643,8 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
afar_reg = base + SCHIZO_PCI_AFAR;
/* Latch error status. */
- afar = schizo_read(afar_reg);
- afsr = schizo_read(afsr_reg);
+ afar = upa_readq(afar_reg);
+ afsr = upa_readq(afsr_reg);
/* Clear primary/secondary error status bits. */
error_bits = afsr &
@@ -674,7 +656,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
if (!error_bits)
return schizo_pcierr_intr_other(pbm);
- schizo_write(afsr_reg, error_bits);
+ upa_writeq(error_bits, afsr_reg);
/* Log the error. */
printk("%s: PCI Error, primary error type[%s]\n",
@@ -744,7 +726,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
* a bug in the IOMMU support code or a PCI device driver.
*/
if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
- schizo_check_iommu_error(p, PCI_ERR);
+ schizo_check_iommu_error(pbm, PCI_ERR);
pci_scan_for_target_abort(pbm, pbm->pci_bus);
}
if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
@@ -805,12 +787,11 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
{
struct pci_pbm_info *pbm = dev_id;
- struct pci_controller_info *p = pbm->parent;
u64 errlog;
- errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
- errlog & ~(SAFARI_ERRLOG_ERROUT));
+ errlog = upa_readq(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+ upa_writeq(errlog & ~(SAFARI_ERRLOG_ERROUT),
+ pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
if (!(errlog & BUS_ERROR_UNMAP)) {
printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
@@ -821,7 +802,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
pbm->name);
- schizo_check_iommu_error(p, SAFARI_ERR);
+ schizo_check_iommu_error(pbm, SAFARI_ERR);
return IRQ_HANDLED;
}
@@ -863,7 +844,7 @@ static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
*/
static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->prom_node);
+ struct of_device *op = of_find_device_by_node(pbm->op->node);
u64 tmp, err_mask, err_no_mask;
int err;
@@ -910,10 +891,9 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
}
/* Enable UE and CE interrupts for controller. */
- schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
- (SCHIZO_ECCCTRL_EE |
- SCHIZO_ECCCTRL_UE |
- SCHIZO_ECCCTRL_CE));
+ upa_writeq((SCHIZO_ECCCTRL_EE |
+ SCHIZO_ECCCTRL_UE |
+ SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
/* Enable PCI Error interrupts and clear error
* bits.
@@ -926,10 +906,10 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -938,7 +918,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
SCHIZO_PCIAFSR_STTO);
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+ upa_writeq(err_mask, pbm->pbm_regs + SCHIZO_PCI_AFSR);
err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -950,16 +930,16 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
BUS_ERROR_APERR | BUS_ERROR_UNMAP |
BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
- (SCHIZO_SAFERRCTRL_EN | err_mask));
+ upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+ pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
- (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+ upa_writeq((SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)),
+ pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL);
}
static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct of_device *op = of_find_device_by_node(pbm->prom_node);
+ struct of_device *op = of_find_device_by_node(pbm->op->node);
u64 tmp, err_mask, err_no_mask;
int err;
@@ -1006,10 +986,9 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
}
/* Enable UE and CE interrupts for controller. */
- schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
- (SCHIZO_ECCCTRL_EE |
- SCHIZO_ECCCTRL_UE |
- SCHIZO_ECCCTRL_CE));
+ upa_writeq((SCHIZO_ECCCTRL_EE |
+ SCHIZO_ECCCTRL_UE |
+ SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
SCHIZO_PCICTRL_ESLCK |
@@ -1025,18 +1004,18 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
/* Enable PCI Error interrupts and clear error
* bits for each PBM.
*/
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
- (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
- SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
- SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
- SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
- SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
- SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
+ upa_writeq((SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+ SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+ SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+ SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+ SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+ SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS),
+ pbm->pbm_regs + SCHIZO_PCI_AFSR);
/* Make all Safari error conditions fatal except unmapped
* errors which we make generate interrupts.
@@ -1063,8 +1042,8 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
#endif
- schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
- (SCHIZO_SAFERRCTRL_EN | err_mask));
+ upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+ pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
}
static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1084,14 +1063,15 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}
-static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
pbm_config_busmastering(pbm);
pbm->is_66mhz_capable =
- (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
+ (of_find_property(pbm->op->node, "66mhz-capable", NULL)
!= NULL);
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
tomatillo_register_error_handlers(pbm);
@@ -1133,12 +1113,12 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
* streaming buffer and leave the rerun-disable
* setting however OBP set it.
*/
- control = schizo_read(pbm->stc.strbuf_control);
+ control = upa_readq(pbm->stc.strbuf_control);
control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
SCHIZO_STRBUF_CTRL_LENAB |
SCHIZO_STRBUF_CTRL_DENAB);
control |= SCHIZO_STRBUF_CTRL_ENAB;
- schizo_write(pbm->stc.strbuf_control, control);
+ upa_writeq(control, pbm->stc.strbuf_control);
pbm->stc.strbuf_enabled = 1;
}
@@ -1150,24 +1130,17 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
- struct iommu *iommu = pbm->iommu;
+ static const u32 vdma_default[] = { 0xc0000000, 0x40000000 };
unsigned long i, tagbase, database;
- struct property *prop;
- u32 vdma[2], dma_mask;
+ struct iommu *iommu = pbm->iommu;
int tsbsize, err;
+ const u32 *vdma;
+ u32 dma_mask;
u64 control;
- prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
- if (prop) {
- u32 *val = prop->value;
-
- vdma[0] = val[0];
- vdma[1] = val[1];
- } else {
- /* No property, use default values. */
- vdma[0] = 0xc0000000;
- vdma[1] = 0x40000000;
- }
+ vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+ if (!vdma)
+ vdma = vdma_default;
dma_mask = vdma[0];
switch (vdma[1]) {
@@ -1187,9 +1160,9 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
break;
default:
- prom_printf("SCHIZO: strange virtual-dma size.\n");
- prom_halt();
- };
+ printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+ return -EINVAL;
+ }
/* Register addresses, SCHIZO has iommu ctx flushing. */
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1206,15 +1179,15 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
/*
* Invalidate TLB Entries.
*/
- control = schizo_read(iommu->iommu_control);
+ control = upa_readq(iommu->iommu_control);
control |= SCHIZO_IOMMU_CTRL_DENAB;
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
- for(i = 0; i < 16; i++) {
- schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
- schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
+ for (i = 0; i < 16; i++) {
+ upa_writeq(0, pbm->pbm_regs + tagbase + (i * 8UL));
+ upa_writeq(0, pbm->pbm_regs + database + (i * 8UL));
}
/* Leave diag mode enabled for full-flushing done
@@ -1222,12 +1195,14 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
*/
err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
pbm->numa_node);
- if (err)
+ if (err) {
+ printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err);
return err;
+ }
- schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
+ upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
- control = schizo_read(iommu->iommu_control);
+ control = upa_readq(iommu->iommu_control);
control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
switch (tsbsize) {
case 64:
@@ -1236,10 +1211,10 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
case 128:
control |= SCHIZO_IOMMU_TSBSZ_128K;
break;
- };
+ }
control |= SCHIZO_IOMMU_CTRL_ENAB;
- schizo_write(iommu->iommu_control, control);
+ upa_writeq(control, iommu->iommu_control);
return 0;
}
@@ -1280,12 +1255,11 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
- struct property *prop;
u64 tmp;
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
+ upa_writeq(5, pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY);
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
/* Enable arbiter for all PCI slots. */
tmp |= 0xff;
@@ -1294,8 +1268,7 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
- prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
- if (!prop)
+ if (!of_find_property(pbm->op->node, "no-bus-parking", NULL))
tmp |= SCHIZO_PCICTRL_PARK;
else
tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1311,13 +1284,13 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
SCHIZO_PCICTRL_RDO_PREF |
SCHIZO_PCICTRL_RDL_PREF);
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
- tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG);
+ tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_DIAG);
tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB |
SCHIZO_PCIDIAG_D_RETRY |
SCHIZO_PCIDIAG_D_INTSYNC);
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp);
+ upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_DIAG);
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
/* Clear prefetch lengths to workaround a bug in
@@ -1329,17 +1302,16 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
TOMATILLO_IOC_RDONE_CPENAB |
TOMATILLO_IOC_RDLINE_CPENAB);
- schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR,
- tmp);
+ upa_writeq(tmp, pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR);
}
}
-static int __init schizo_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid,
- int chip_type)
+static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, u32 portid,
+ int chip_type)
{
const struct linux_prom64_registers *regs;
- struct pci_pbm_info *pbm;
+ struct device_node *dp = op->node;
const char *chipset_name;
int is_pbm_a, err;
@@ -1372,25 +1344,19 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
regs = of_get_property(dp, "reg", NULL);
is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
- if (is_pbm_a)
- pbm = &p->pbm_A;
- else
- pbm = &p->pbm_B;
pbm->next = pci_pbm_root;
pci_pbm_root = pbm;
pbm->numa_node = -1;
- pbm->scan_bus = schizo_scan_bus;
pbm->pci_ops = &sun4u_pci_ops;
pbm->config_space_reg_bits = 8;
pbm->index = pci_num_pbms++;
pbm->portid = portid;
- pbm->parent = p;
- pbm->prom_node = dp;
+ pbm->op = op;
pbm->chip_type = chip_type;
pbm->chip_version = of_getintprop_default(dp, "version#", 0);
@@ -1420,6 +1386,8 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
schizo_pbm_strbuf_init(pbm);
+ schizo_scan_bus(pbm, &op->dev);
+
return 0;
}
@@ -1433,62 +1401,104 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
return (x == y);
}
-static void __init __schizo_init(struct device_node *dp, char *model_name,
- int chip_type)
+static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
+ int chip_type)
{
- struct pci_controller_info *p;
+ struct pci_pbm_info *pbm;
+
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+ if (portid_compare(pbm->portid, portid, chip_type))
+ return pbm;
+ }
+ return NULL;
+}
+
+static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
+{
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
struct iommu *iommu;
u32 portid;
+ int err;
portid = of_getintprop_default(dp, "portid", 0xff);
- for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
- if (portid_compare(pbm->portid, portid, chip_type)) {
- if (schizo_pbm_init(pbm->parent, dp,
- portid, chip_type))
- goto fatal_memory_error;
- return;
- }
+ err = -ENOMEM;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+ goto out_err;
+ }
+
+ pbm->sibling = schizo_find_sibling(portid, chip_type);
+
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
+ goto out_free_pbm;
}
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ pbm->iommu = iommu;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ if (schizo_pbm_init(pbm, op, portid, chip_type))
+ goto out_free_iommu;
- p->pbm_A.iommu = iommu;
+ if (pbm->sibling)
+ pbm->sibling->sibling = pbm;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ dev_set_drvdata(&op->dev, pbm);
- p->pbm_B.iommu = iommu;
+ return 0;
- if (schizo_pbm_init(p, dp, portid, chip_type))
- goto fatal_memory_error;
+out_free_iommu:
+ kfree(pbm->iommu);
- return;
+out_free_pbm:
+ kfree(pbm);
-fatal_memory_error:
- prom_printf("SCHIZO: Fatal memory allocation error.\n");
- prom_halt();
+out_err:
+ return err;
}
-void __init schizo_init(struct device_node *dp, char *model_name)
+static int __devinit schizo_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
+ return __schizo_init(op, (unsigned long) match->data);
}
-void __init schizo_plus_init(struct device_node *dp, char *model_name)
-{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
-}
+/* The ordering of this table is very important. Some Tomatillo
+ * nodes announce that they are compatible with both pci108e,a801
+ * and pci108e,8001. So list the chips in reverse chronological
+ * order.
+ */
+static struct of_device_id __initdata schizo_match[] = {
+ {
+ .name = "pci",
+ .compatible = "pci108e,a801",
+ .data = (void *) PBM_CHIP_TYPE_TOMATILLO,
+ },
+ {
+ .name = "pci",
+ .compatible = "pci108e,8002",
+ .data = (void *) PBM_CHIP_TYPE_SCHIZO_PLUS,
+ },
+ {
+ .name = "pci",
+ .compatible = "pci108e,8001",
+ .data = (void *) PBM_CHIP_TYPE_SCHIZO,
+ },
+ {},
+};
-void __init tomatillo_init(struct device_node *dp, char *model_name)
+static struct of_platform_driver schizo_driver = {
+ .name = DRIVER_NAME,
+ .match_table = schizo_match,
+ .probe = schizo_probe,
+};
+
+static int __init schizo_init(void)
{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
+ return of_register_driver(&schizo_driver, &of_bus_type);
}
+
+subsys_initcall(schizo_init);
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index a104c80d319..e86c73ec167 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -13,12 +13,10 @@
#include <linux/irq.h>
#include <linux/msi.h>
#include <linux/log2.h>
+#include <linux/of_device.h>
#include <asm/iommu.h>
#include <asm/irq.h>
-#include <asm/upa.h>
-#include <asm/pstate.h>
-#include <asm/oplib.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
@@ -27,6 +25,9 @@
#include "pci_sun4v.h"
+#define DRIVER_NAME "pci_sun4v"
+#define PFX DRIVER_NAME ": "
+
static unsigned long vpci_major = 1;
static unsigned long vpci_minor = 1;
@@ -41,6 +42,7 @@ struct iommu_batch {
};
static DEFINE_PER_CPU(struct iommu_batch, iommu_batch);
+static int iommu_batch_initialized;
/* Interrupts must be disabled. */
static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry)
@@ -542,15 +544,16 @@ static const struct dma_ops sun4v_dma_ops = {
.sync_sg_for_cpu = dma_4v_sync_sg_for_cpu,
};
-static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
struct property *prop;
struct device_node *dp;
- dp = pbm->prom_node;
+ dp = pbm->op->node;
prop = of_find_property(dp, "66mhz-capable", NULL);
pbm->is_66mhz_capable = (prop != NULL);
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
/* XXX register error interrupt handlers XXX */
}
@@ -583,29 +586,22 @@ static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm,
return cnt;
}
-static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
{
+ static const u32 vdma_default[] = { 0x80000000, 0x80000000 };
struct iommu *iommu = pbm->iommu;
- struct property *prop;
unsigned long num_tsb_entries, sz, tsbsize;
- u32 vdma[2], dma_mask, dma_offset;
-
- prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
- if (prop) {
- u32 *val = prop->value;
-
- vdma[0] = val[0];
- vdma[1] = val[1];
- } else {
- /* No property, use default values. */
- vdma[0] = 0x80000000;
- vdma[1] = 0x80000000;
- }
+ u32 dma_mask, dma_offset;
+ const u32 *vdma;
+
+ vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+ if (!vdma)
+ vdma = vdma_default;
if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
- prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
- vdma[0], vdma[1]);
- prom_halt();
+ printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n",
+ vdma[0], vdma[1]);
+ return -EINVAL;
};
dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
@@ -625,8 +621,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
sz = (sz + 7UL) & ~7UL;
iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) {
- prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
- prom_halt();
+ printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n");
+ return -ENOMEM;
}
iommu->arena.limit = num_tsb_entries;
@@ -634,6 +630,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
if (sz)
printk("%s: Imported %lu TSB entries from OBP\n",
pbm->name, sz);
+
+ return 0;
}
#ifdef CONFIG_PCI_MSI
@@ -890,29 +888,20 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
}
#endif /* !(CONFIG_PCI_MSI) */
-static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 devhandle)
+static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
+ struct of_device *op, u32 devhandle)
{
- struct pci_pbm_info *pbm;
-
- if (devhandle & 0x40)
- pbm = &p->pbm_B;
- else
- pbm = &p->pbm_A;
-
- pbm->next = pci_pbm_root;
- pci_pbm_root = pbm;
+ struct device_node *dp = op->node;
+ int err;
pbm->numa_node = of_node_to_nid(dp);
- pbm->scan_bus = pci_sun4v_scan_bus;
pbm->pci_ops = &sun4v_pci_ops;
pbm->config_space_reg_bits = 12;
pbm->index = pci_num_pbms++;
- pbm->parent = p;
- pbm->prom_node = dp;
+ pbm->op = op;
pbm->devhandle = devhandle;
@@ -924,82 +913,120 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
pci_determine_mem_io_space(pbm);
pci_get_pbm_props(pbm);
- pci_sun4v_iommu_init(pbm);
+
+ err = pci_sun4v_iommu_init(pbm);
+ if (err)
+ return err;
+
pci_sun4v_msi_init(pbm);
+
+ pci_sun4v_scan_bus(pbm, &op->dev);
+
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ return 0;
}
-void __init sun4v_pci_init(struct device_node *dp, char *model_name)
+static int __devinit pci_sun4v_probe(struct of_device *op,
+ const struct of_device_id *match)
{
+ const struct linux_prom64_registers *regs;
static int hvapi_negotiated = 0;
- struct pci_controller_info *p;
struct pci_pbm_info *pbm;
+ struct device_node *dp;
struct iommu *iommu;
- struct property *prop;
- struct linux_prom64_registers *regs;
u32 devhandle;
- int i;
+ int i, err;
+
+ dp = op->node;
if (!hvapi_negotiated++) {
- int err = sun4v_hvapi_register(HV_GRP_PCI,
- vpci_major,
- &vpci_minor);
+ err = sun4v_hvapi_register(HV_GRP_PCI,
+ vpci_major,
+ &vpci_minor);
if (err) {
- prom_printf("SUN4V_PCI: Could not register hvapi, "
- "err=%d\n", err);
- prom_halt();
+ printk(KERN_ERR PFX "Could not register hvapi, "
+ "err=%d\n", err);
+ return err;
}
- printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n",
+ printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n",
vpci_major, vpci_minor);
dma_ops = &sun4v_dma_ops;
}
- prop = of_find_property(dp, "reg", NULL);
- if (!prop) {
- prom_printf("SUN4V_PCI: Could not find config registers\n");
- prom_halt();
+ regs = of_get_property(dp, "reg", NULL);
+ err = -ENODEV;
+ if (!regs) {
+ printk(KERN_ERR PFX "Could not find config registers\n");
+ goto out_err;
}
- regs = prop->value;
-
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
- for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
- if (pbm->devhandle == (devhandle ^ 0x40)) {
- pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
- return;
+ err = -ENOMEM;
+ if (!iommu_batch_initialized) {
+ for_each_possible_cpu(i) {
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+ if (!page)
+ goto out_err;
+
+ per_cpu(iommu_batch, i).pglist = (u64 *) page;
}
+ iommu_batch_initialized = 1;
}
- for_each_possible_cpu(i) {
- unsigned long page = get_zeroed_page(GFP_ATOMIC);
-
- if (!page)
- goto fatal_memory_error;
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+ if (!pbm) {
+ printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n");
+ goto out_err;
+ }
- per_cpu(iommu_batch, i).pglist = (u64 *) page;
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+ if (!iommu) {
+ printk(KERN_ERR PFX "Could not allocate pbm iommu\n");
+ goto out_free_controller;
}
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ pbm->iommu = iommu;
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ err = pci_sun4v_pbm_init(pbm, op, devhandle);
+ if (err)
+ goto out_free_iommu;
+
+ dev_set_drvdata(&op->dev, pbm);
+
+ return 0;
+
+out_free_iommu:
+ kfree(pbm->iommu);
- p->pbm_A.iommu = iommu;
+out_free_controller:
+ kfree(pbm);
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+out_err:
+ return err;
+}
- p->pbm_B.iommu = iommu;
+static struct of_device_id __initdata pci_sun4v_match[] = {
+ {
+ .name = "pci",
+ .compatible = "SUNW,sun4v-pci",
+ },
+ {},
+};
- pci_sun4v_pbm_init(p, dp, devhandle);
- return;
+static struct of_platform_driver pci_sun4v_driver = {
+ .name = DRIVER_NAME,
+ .match_table = pci_sun4v_match,
+ .probe = pci_sun4v_probe,
+};
-fatal_memory_error:
- prom_printf("SUN4V_PCI: Fatal memory allocation error.\n");
- prom_halt();
+static int __init pci_sun4v_init(void)
+{
+ return of_register_driver(&pci_sun4v_driver, &of_bus_type);
}
+
+subsys_initcall(pci_sun4v_init);
diff --git a/arch/sparc64/kernel/pci_sun4v_asm.S b/arch/sparc64/kernel/pci_sun4v_asm.S
index ecb81f389b0..e606d46c681 100644
--- a/arch/sparc64/kernel/pci_sun4v_asm.S
+++ b/arch/sparc64/kernel/pci_sun4v_asm.S
@@ -1,8 +1,9 @@
/* pci_sun4v_asm: Hypervisor calls for PCI support.
*
- * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2006, 2008 David S. Miller <davem@davemloft.net>
*/
+#include <linux/linkage.h>
#include <asm/hypervisor.h>
/* %o0: devhandle
@@ -14,8 +15,7 @@
* returns %o0: -status if status was non-zero, else
* %o0: num pages mapped
*/
- .globl pci_sun4v_iommu_map
-pci_sun4v_iommu_map:
+ENTRY(pci_sun4v_iommu_map)
mov %o5, %g1
mov HV_FAST_PCI_IOMMU_MAP, %o5
ta HV_FAST_TRAP
@@ -24,6 +24,7 @@ pci_sun4v_iommu_map:
mov %o1, %o0
1: retl
nop
+ENDPROC(pci_sun4v_iommu_map)
/* %o0: devhandle
* %o1: tsbid
@@ -31,12 +32,12 @@ pci_sun4v_iommu_map:
*
* returns %o0: num ttes demapped
*/
- .globl pci_sun4v_iommu_demap
-pci_sun4v_iommu_demap:
+ENTRY(pci_sun4v_iommu_demap)
mov HV_FAST_PCI_IOMMU_DEMAP, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
+ENDPROC(pci_sun4v_iommu_demap)
/* %o0: devhandle
* %o1: tsbid
@@ -45,8 +46,7 @@ pci_sun4v_iommu_demap:
*
* returns %o0: status
*/
- .globl pci_sun4v_iommu_getmap
-pci_sun4v_iommu_getmap:
+ENTRY(pci_sun4v_iommu_getmap)
mov %o2, %o4
mov HV_FAST_PCI_IOMMU_GETMAP, %o5
ta HV_FAST_TRAP
@@ -54,6 +54,7 @@ pci_sun4v_iommu_getmap:
stx %o2, [%o3]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_iommu_getmap)
/* %o0: devhandle
* %o1: pci_device
@@ -65,14 +66,14 @@ pci_sun4v_iommu_getmap:
* If there is an error, the data will be returned
* as all 1's.
*/
- .globl pci_sun4v_config_get
-pci_sun4v_config_get:
+ENTRY(pci_sun4v_config_get)
mov HV_FAST_PCI_CONFIG_GET, %o5
ta HV_FAST_TRAP
brnz,a,pn %o1, 1f
mov -1, %o2
1: retl
mov %o2, %o0
+ENDPROC(pci_sun4v_config_get)
/* %o0: devhandle
* %o1: pci_device
@@ -85,14 +86,14 @@ pci_sun4v_config_get:
* status will be zero if the operation completed
* successfully, else -1 if not
*/
- .globl pci_sun4v_config_put
-pci_sun4v_config_put:
+ENTRY(pci_sun4v_config_put)
mov HV_FAST_PCI_CONFIG_PUT, %o5
ta HV_FAST_TRAP
brnz,a,pn %o1, 1f
mov -1, %o1
1: retl
mov %o1, %o0
+ENDPROC(pci_sun4v_config_put)
/* %o0: devhandle
* %o1: msiqid
@@ -104,12 +105,12 @@ pci_sun4v_config_put:
* status will be zero if the operation completed
* successfully, else -1 if not
*/
- .globl pci_sun4v_msiq_conf
-pci_sun4v_msiq_conf:
+ENTRY(pci_sun4v_msiq_conf)
mov HV_FAST_PCI_MSIQ_CONF, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_conf)
/* %o0: devhandle
* %o1: msiqid
@@ -118,8 +119,7 @@ pci_sun4v_msiq_conf:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_info
-pci_sun4v_msiq_info:
+ENTRY(pci_sun4v_msiq_info)
mov %o2, %o4
mov HV_FAST_PCI_MSIQ_INFO, %o5
ta HV_FAST_TRAP
@@ -127,6 +127,7 @@ pci_sun4v_msiq_info:
stx %o2, [%o3]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_info)
/* %o0: devhandle
* %o1: msiqid
@@ -134,13 +135,13 @@ pci_sun4v_msiq_info:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_getvalid
-pci_sun4v_msiq_getvalid:
+ENTRY(pci_sun4v_msiq_getvalid)
mov HV_FAST_PCI_MSIQ_GETVALID, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_getvalid)
/* %o0: devhandle
* %o1: msiqid
@@ -148,12 +149,12 @@ pci_sun4v_msiq_getvalid:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_setvalid
-pci_sun4v_msiq_setvalid:
+ENTRY(pci_sun4v_msiq_setvalid)
mov HV_FAST_PCI_MSIQ_SETVALID, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_setvalid)
/* %o0: devhandle
* %o1: msiqid
@@ -161,13 +162,13 @@ pci_sun4v_msiq_setvalid:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_getstate
-pci_sun4v_msiq_getstate:
+ENTRY(pci_sun4v_msiq_getstate)
mov HV_FAST_PCI_MSIQ_GETSTATE, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_getstate)
/* %o0: devhandle
* %o1: msiqid
@@ -175,12 +176,12 @@ pci_sun4v_msiq_getstate:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_setstate
-pci_sun4v_msiq_setstate:
+ENTRY(pci_sun4v_msiq_setstate)
mov HV_FAST_PCI_MSIQ_SETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_setstate)
/* %o0: devhandle
* %o1: msiqid
@@ -188,13 +189,13 @@ pci_sun4v_msiq_setstate:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_gethead
-pci_sun4v_msiq_gethead:
+ENTRY(pci_sun4v_msiq_gethead)
mov HV_FAST_PCI_MSIQ_GETHEAD, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_gethead)
/* %o0: devhandle
* %o1: msiqid
@@ -202,12 +203,12 @@ pci_sun4v_msiq_gethead:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_sethead
-pci_sun4v_msiq_sethead:
+ENTRY(pci_sun4v_msiq_sethead)
mov HV_FAST_PCI_MSIQ_SETHEAD, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_sethead)
/* %o0: devhandle
* %o1: msiqid
@@ -215,13 +216,13 @@ pci_sun4v_msiq_sethead:
*
* returns %o0: status
*/
- .globl pci_sun4v_msiq_gettail
-pci_sun4v_msiq_gettail:
+ENTRY(pci_sun4v_msiq_gettail)
mov HV_FAST_PCI_MSIQ_GETTAIL, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msiq_gettail)
/* %o0: devhandle
* %o1: msinum
@@ -229,13 +230,13 @@ pci_sun4v_msiq_gettail:
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_getvalid
-pci_sun4v_msi_getvalid:
+ENTRY(pci_sun4v_msi_getvalid)
mov HV_FAST_PCI_MSI_GETVALID, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msi_getvalid)
/* %o0: devhandle
* %o1: msinum
@@ -243,12 +244,12 @@ pci_sun4v_msi_getvalid:
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_setvalid
-pci_sun4v_msi_setvalid:
+ENTRY(pci_sun4v_msi_setvalid)
mov HV_FAST_PCI_MSI_SETVALID, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msi_setvalid)
/* %o0: devhandle
* %o1: msinum
@@ -256,13 +257,13 @@ pci_sun4v_msi_setvalid:
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_getmsiq
-pci_sun4v_msi_getmsiq:
+ENTRY(pci_sun4v_msi_getmsiq)
mov HV_FAST_PCI_MSI_GETMSIQ, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msi_getmsiq)
/* %o0: devhandle
* %o1: msinum
@@ -271,12 +272,12 @@ pci_sun4v_msi_getmsiq:
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_setmsiq
-pci_sun4v_msi_setmsiq:
+ENTRY(pci_sun4v_msi_setmsiq)
mov HV_FAST_PCI_MSI_SETMSIQ, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msi_setmsiq)
/* %o0: devhandle
* %o1: msinum
@@ -284,13 +285,13 @@ pci_sun4v_msi_setmsiq:
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_getstate
-pci_sun4v_msi_getstate:
+ENTRY(pci_sun4v_msi_getstate)
mov HV_FAST_PCI_MSI_GETSTATE, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msi_getstate)
/* %o0: devhandle
* %o1: msinum
@@ -298,12 +299,12 @@ pci_sun4v_msi_getstate:
*
* returns %o0: status
*/
- .globl pci_sun4v_msi_setstate
-pci_sun4v_msi_setstate:
+ENTRY(pci_sun4v_msi_setstate)
mov HV_FAST_PCI_MSI_SETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msi_setstate)
/* %o0: devhandle
* %o1: msinum
@@ -311,13 +312,13 @@ pci_sun4v_msi_setstate:
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_getmsiq
-pci_sun4v_msg_getmsiq:
+ENTRY(pci_sun4v_msg_getmsiq)
mov HV_FAST_PCI_MSG_GETMSIQ, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msg_getmsiq)
/* %o0: devhandle
* %o1: msinum
@@ -325,12 +326,12 @@ pci_sun4v_msg_getmsiq:
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_setmsiq
-pci_sun4v_msg_setmsiq:
+ENTRY(pci_sun4v_msg_setmsiq)
mov HV_FAST_PCI_MSG_SETMSIQ, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msg_setmsiq)
/* %o0: devhandle
* %o1: msinum
@@ -338,13 +339,13 @@ pci_sun4v_msg_setmsiq:
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_getvalid
-pci_sun4v_msg_getvalid:
+ENTRY(pci_sun4v_msg_getvalid)
mov HV_FAST_PCI_MSG_GETVALID, %o5
ta HV_FAST_TRAP
stx %o1, [%o2]
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msg_getvalid)
/* %o0: devhandle
* %o1: msinum
@@ -352,10 +353,10 @@ pci_sun4v_msg_getvalid:
*
* returns %o0: status
*/
- .globl pci_sun4v_msg_setvalid
-pci_sun4v_msg_setvalid:
+ENTRY(pci_sun4v_msg_setvalid)
mov HV_FAST_PCI_MSG_SETVALID, %o5
ta HV_FAST_TRAP
retl
mov %o0, %o0
+ENDPROC(pci_sun4v_msg_setvalid)
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 3bb987a6d03..076cad7f975 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -1,34 +1,17 @@
/* power.c: Power management driver.
*
- * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/syscalls.h>
#include <linux/reboot.h>
#include <linux/of_device.h>
-#include <asm/system.h>
-#include <asm/auxio.h>
#include <asm/prom.h>
#include <asm/io.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
-
-#include <linux/unistd.h>
-
-/*
- * sysctl - toggle power-off restriction for serial console
- * systems in machine_power_off()
- */
-int scons_pwroff = 1;
static void __iomem *power_reg;
@@ -40,31 +23,6 @@ static irqreturn_t power_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void (*poweroff_method)(void) = machine_alt_power_off;
-
-void machine_power_off(void)
-{
- sstate_poweroff();
- if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
- if (power_reg) {
- /* Both register bits seem to have the
- * same effect, so until I figure out
- * what the difference is...
- */
- writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg);
- } else {
- if (poweroff_method != NULL) {
- poweroff_method();
- /* not reached */
- }
- }
- }
- machine_halt();
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
if (irq == 0xffffffff)
@@ -85,8 +43,6 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
printk(KERN_INFO "%s: Control reg at %lx\n",
op->node->name, res->start);
- poweroff_method = machine_halt; /* able to use the standard halt */
-
if (has_button_interrupt(irq, op->node)) {
if (request_irq(irq,
power_handler, 0, "power", NULL) < 0)
@@ -96,7 +52,7 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
return 0;
}
-static struct of_device_id power_match[] = {
+static struct of_device_id __initdata power_match[] = {
{
.name = "power",
},
@@ -111,8 +67,9 @@ static struct of_platform_driver power_driver = {
},
};
-void __init power_init(void)
+static int __init power_init(void)
{
- of_register_driver(&power_driver, &of_platform_bus_type);
- return;
+ return of_register_driver(&power_driver, &of_platform_bus_type);
}
+
+device_initcall(power_init);
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 15f4178592e..d5e2acef987 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -22,7 +22,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
-#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/compat.h>
#include <linux/tick.h>
@@ -31,7 +30,6 @@
#include <linux/elfcore.h>
#include <linux/sysrq.h>
-#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
@@ -46,8 +44,6 @@
#include <asm/mmu_context.h>
#include <asm/unistd.h>
#include <asm/hypervisor.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
#include <asm/syscalls.h>
#include <asm/irq_regs.h>
#include <asm/smp.h>
@@ -115,35 +111,6 @@ void cpu_idle(void)
}
}
-void machine_halt(void)
-{
- sstate_halt();
- prom_halt();
- panic("Halt failed!");
-}
-
-void machine_alt_power_off(void)
-{
- sstate_poweroff();
- prom_halt_power_off();
- panic("Power-off failed!");
-}
-
-void machine_restart(char * cmd)
-{
- char *p;
-
- sstate_reboot();
- p = strchr (reboot_command, '\n');
- if (p) *p = 0;
- if (cmd)
- prom_reboot(cmd);
- if (*reboot_command)
- prom_reboot(reboot_command);
- prom_reboot("");
- panic("Reboot failed!");
-}
-
#ifdef CONFIG_COMPAT
static void show_regwindow32(struct pt_regs *regs)
{
@@ -248,7 +215,6 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7];
if (regs->tstate & TSTATE_PRIV) {
- struct thread_info *tp = current_thread_info();
struct reg_window *rw;
rw = (struct reg_window *)
@@ -304,7 +270,6 @@ void __trigger_all_cpu_backtrace(void)
for_each_online_cpu(cpu) {
struct global_reg_snapshot *gp = &global_reg_snapshot[cpu];
- struct thread_info *tp;
__global_reg_poll(gp);
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 7151513f156..dbba82f9b14 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -38,7 +38,7 @@ struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
- for (np = allnodes; np != 0; np = np->allnext)
+ for (np = allnodes; np; np = np->allnext)
if (np->node == handle)
break;
@@ -59,6 +59,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
}
EXPORT_SYMBOL(of_getintprop_default);
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
int of_set_property(struct device_node *dp, const char *name, void *val, int len)
{
struct property **prevp;
@@ -82,7 +85,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
void *old_val = prop->value;
int ret;
+ mutex_lock(&of_set_property_mutex);
ret = prom_setprop(dp->node, name, val, len);
+ mutex_unlock(&of_set_property_mutex);
+
err = -EINVAL;
if (ret >= 0) {
prop->value = new_val;
@@ -945,22 +951,30 @@ static void __init irq_trans_init(struct device_node *dp)
for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
struct irq_trans *t = &pci_irq_trans_table[i];
- if (!strcmp(model, t->name))
- return t->init(dp);
+ if (!strcmp(model, t->name)) {
+ t->init(dp);
+ return;
+ }
}
}
#endif
#ifdef CONFIG_SBUS
if (!strcmp(dp->name, "sbus") ||
- !strcmp(dp->name, "sbi"))
- return sbus_irq_trans_init(dp);
+ !strcmp(dp->name, "sbi")) {
+ sbus_irq_trans_init(dp);
+ return;
+ }
#endif
if (!strcmp(dp->name, "fhc") &&
- !strcmp(dp->parent->name, "central"))
- return central_irq_trans_init(dp);
+ !strcmp(dp->parent->name, "central")) {
+ central_irq_trans_init(dp);
+ return;
+ }
if (!strcmp(dp->name, "virtual-devices") ||
- !strcmp(dp->name, "niu"))
- return sun4v_vdev_irq_trans_init(dp);
+ !strcmp(dp->name, "niu")) {
+ sun4v_vdev_irq_trans_init(dp);
+ return;
+ }
}
static int is_root_node(const struct device_node *dp)
@@ -1231,32 +1245,49 @@ static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
if (parent != NULL) {
if (!strcmp(parent->type, "pci") ||
- !strcmp(parent->type, "pciex"))
- return pci_path_component(dp, tmp_buf);
- if (!strcmp(parent->type, "sbus"))
- return sbus_path_component(dp, tmp_buf);
- if (!strcmp(parent->type, "upa"))
- return upa_path_component(dp, tmp_buf);
- if (!strcmp(parent->type, "ebus"))
- return ebus_path_component(dp, tmp_buf);
+ !strcmp(parent->type, "pciex")) {
+ pci_path_component(dp, tmp_buf);
+ return;
+ }
+ if (!strcmp(parent->type, "sbus")) {
+ sbus_path_component(dp, tmp_buf);
+ return;
+ }
+ if (!strcmp(parent->type, "upa")) {
+ upa_path_component(dp, tmp_buf);
+ return;
+ }
+ if (!strcmp(parent->type, "ebus")) {
+ ebus_path_component(dp, tmp_buf);
+ return;
+ }
if (!strcmp(parent->name, "usb") ||
- !strcmp(parent->name, "hub"))
- return usb_path_component(dp, tmp_buf);
- if (!strcmp(parent->type, "i2c"))
- return i2c_path_component(dp, tmp_buf);
- if (!strcmp(parent->type, "firewire"))
- return ieee1394_path_component(dp, tmp_buf);
- if (!strcmp(parent->type, "virtual-devices"))
- return vdev_path_component(dp, tmp_buf);
-
+ !strcmp(parent->name, "hub")) {
+ usb_path_component(dp, tmp_buf);
+ return;
+ }
+ if (!strcmp(parent->type, "i2c")) {
+ i2c_path_component(dp, tmp_buf);
+ return;
+ }
+ if (!strcmp(parent->type, "firewire")) {
+ ieee1394_path_component(dp, tmp_buf);
+ return;
+ }
+ if (!strcmp(parent->type, "virtual-devices")) {
+ vdev_path_component(dp, tmp_buf);
+ return;
+ }
/* "isa" is handled with platform naming */
}
/* Use platform naming convention. */
- if (tlb_type == hypervisor)
- return sun4v_path_component(dp, tmp_buf);
- else
- return sun4u_path_component(dp, tmp_buf);
+ if (tlb_type == hypervisor) {
+ sun4v_path_component(dp, tmp_buf);
+ return;
+ } else {
+ sun4u_path_component(dp, tmp_buf);
+ }
}
static char * __init build_path_component(struct device_node *dp)
diff --git a/arch/sparc64/kernel/psycho_common.c b/arch/sparc64/kernel/psycho_common.c
new file mode 100644
index 00000000000..790996428c1
--- /dev/null
+++ b/arch/sparc64/kernel/psycho_common.c
@@ -0,0 +1,470 @@
+/* psycho_common.c: Code common to PSYCHO and derivative PCI controllers.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#include <asm/upa.h>
+
+#include "pci_impl.h"
+#include "iommu_common.h"
+#include "psycho_common.h"
+
+#define PSYCHO_STRBUF_CTRL_DENAB 0x0000000000000002UL
+#define PSYCHO_STCERR_WRITE 0x0000000000000002UL
+#define PSYCHO_STCERR_READ 0x0000000000000001UL
+#define PSYCHO_STCTAG_PPN 0x0fffffff00000000UL
+#define PSYCHO_STCTAG_VPN 0x00000000ffffe000UL
+#define PSYCHO_STCTAG_VALID 0x0000000000000002UL
+#define PSYCHO_STCTAG_WRITE 0x0000000000000001UL
+#define PSYCHO_STCLINE_LINDX 0x0000000001e00000UL
+#define PSYCHO_STCLINE_SPTR 0x00000000001f8000UL
+#define PSYCHO_STCLINE_LADDR 0x0000000000007f00UL
+#define PSYCHO_STCLINE_EPTR 0x00000000000000fcUL
+#define PSYCHO_STCLINE_VALID 0x0000000000000002UL
+#define PSYCHO_STCLINE_FOFN 0x0000000000000001UL
+
+static DEFINE_SPINLOCK(stc_buf_lock);
+static unsigned long stc_error_buf[128];
+static unsigned long stc_tag_buf[16];
+static unsigned long stc_line_buf[16];
+
+static void psycho_check_stc_error(struct pci_pbm_info *pbm)
+{
+ unsigned long err_base, tag_base, line_base;
+ struct strbuf *strbuf = &pbm->stc;
+ u64 control;
+ int i;
+
+ if (!strbuf->strbuf_control)
+ return;
+
+ err_base = strbuf->strbuf_err_stat;
+ tag_base = strbuf->strbuf_tag_diag;
+ line_base = strbuf->strbuf_line_diag;
+
+ spin_lock(&stc_buf_lock);
+
+ /* This is __REALLY__ dangerous. When we put the streaming
+ * buffer into diagnostic mode to probe it's tags and error
+ * status, we _must_ clear all of the line tag valid bits
+ * before re-enabling the streaming buffer. If any dirty data
+ * lives in the STC when we do this, we will end up
+ * invalidating it before it has a chance to reach main
+ * memory.
+ */
+ control = upa_readq(strbuf->strbuf_control);
+ upa_writeq(control | PSYCHO_STRBUF_CTRL_DENAB, strbuf->strbuf_control);
+ for (i = 0; i < 128; i++) {
+ u64 val;
+
+ val = upa_readq(err_base + (i * 8UL));
+ upa_writeq(0UL, err_base + (i * 8UL));
+ stc_error_buf[i] = val;
+ }
+ for (i = 0; i < 16; i++) {
+ stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+ stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+ upa_writeq(0UL, tag_base + (i * 8UL));
+ upa_writeq(0UL, line_base + (i * 8UL));
+ }
+
+ /* OK, state is logged, exit diagnostic mode. */
+ upa_writeq(control, strbuf->strbuf_control);
+
+ for (i = 0; i < 16; i++) {
+ int j, saw_error, first, last;
+
+ saw_error = 0;
+ first = i * 8;
+ last = first + 8;
+ for (j = first; j < last; j++) {
+ u64 errval = stc_error_buf[j];
+ if (errval != 0) {
+ saw_error++;
+ printk(KERN_ERR "%s: STC_ERR(%d)[wr(%d)"
+ "rd(%d)]\n",
+ pbm->name,
+ j,
+ (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
+ (errval & PSYCHO_STCERR_READ) ? 1 : 0);
+ }
+ }
+ if (saw_error != 0) {
+ u64 tagval = stc_tag_buf[i];
+ u64 lineval = stc_line_buf[i];
+ printk(KERN_ERR "%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)"
+ "V(%d)W(%d)]\n",
+ pbm->name,
+ i,
+ ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
+ (tagval & PSYCHO_STCTAG_VPN),
+ ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
+ ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
+ printk(KERN_ERR "%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)"
+ "LADDR(%lx)EP(%lx)V(%d)FOFN(%d)]\n",
+ pbm->name,
+ i,
+ ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
+ ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
+ ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
+ ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
+ ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
+ ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
+ }
+ }
+
+ spin_unlock(&stc_buf_lock);
+}
+
+#define PSYCHO_IOMMU_TAG 0xa580UL
+#define PSYCHO_IOMMU_DATA 0xa600UL
+
+static void psycho_record_iommu_tags_and_data(struct pci_pbm_info *pbm,
+ u64 *tag, u64 *data)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ unsigned long base = pbm->controller_regs;
+ unsigned long off = i * 8UL;
+
+ tag[i] = upa_readq(base + PSYCHO_IOMMU_TAG+off);
+ data[i] = upa_readq(base + PSYCHO_IOMMU_DATA+off);
+
+ /* Now clear out the entry. */
+ upa_writeq(0, base + PSYCHO_IOMMU_TAG + off);
+ upa_writeq(0, base + PSYCHO_IOMMU_DATA + off);
+ }
+}
+
+#define PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
+#define PSYCHO_IOMMU_TAG_ERR (0x1UL << 22UL)
+#define PSYCHO_IOMMU_TAG_WRITE (0x1UL << 21UL)
+#define PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
+#define PSYCHO_IOMMU_TAG_SIZE (0x1UL << 19UL)
+#define PSYCHO_IOMMU_TAG_VPAGE 0x7ffffUL
+#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
+#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
+#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
+
+static void psycho_dump_iommu_tags_and_data(struct pci_pbm_info *pbm,
+ u64 *tag, u64 *data)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ u64 tag_val, data_val;
+ const char *type_str;
+ tag_val = tag[i];
+ if (!(tag_val & PSYCHO_IOMMU_TAG_ERR))
+ continue;
+
+ data_val = data[i];
+ switch((tag_val & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
+ case 0:
+ type_str = "Protection Error";
+ break;
+ case 1:
+ type_str = "Invalid Error";
+ break;
+ case 2:
+ type_str = "TimeOut Error";
+ break;
+ case 3:
+ default:
+ type_str = "ECC Error";
+ break;
+ }
+
+ printk(KERN_ERR "%s: IOMMU TAG(%d)[error(%s) wr(%d) "
+ "str(%d) sz(%dK) vpg(%08lx)]\n",
+ pbm->name, i, type_str,
+ ((tag_val & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
+ ((tag_val & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
+ ((tag_val & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
+ (tag_val & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
+ printk(KERN_ERR "%s: IOMMU DATA(%d)[valid(%d) cache(%d) "
+ "ppg(%016lx)]\n",
+ pbm->name, i,
+ ((data_val & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
+ ((data_val & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
+ (data_val & PSYCHO_IOMMU_DATA_PPAGE)<<IOMMU_PAGE_SHIFT);
+ }
+}
+
+#define PSYCHO_IOMMU_CTRL_XLTESTAT 0x0000000006000000UL
+#define PSYCHO_IOMMU_CTRL_XLTEERR 0x0000000001000000UL
+
+void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+ unsigned long afsr,
+ unsigned long afar,
+ enum psycho_error_type type)
+{
+ u64 control, iommu_tag[16], iommu_data[16];
+ struct iommu *iommu = pbm->iommu;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ control = upa_readq(iommu->iommu_control);
+ if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
+ const char *type_str;
+
+ control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
+ upa_writeq(control, iommu->iommu_control);
+
+ switch ((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
+ case 0:
+ type_str = "Protection Error";
+ break;
+ case 1:
+ type_str = "Invalid Error";
+ break;
+ case 2:
+ type_str = "TimeOut Error";
+ break;
+ case 3:
+ default:
+ type_str = "ECC Error";
+ break;
+ };
+ printk(KERN_ERR "%s: IOMMU Error, type[%s]\n",
+ pbm->name, type_str);
+
+ /* It is very possible for another DVMA to occur while
+ * we do this probe, and corrupt the system further.
+ * But we are so screwed at this point that we are
+ * likely to crash hard anyways, so get as much
+ * diagnostic information to the console as we can.
+ */
+ psycho_record_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+ psycho_dump_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+ }
+ psycho_check_stc_error(pbm);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000UL
+#define PSYCHO_PCICTRL_SERR 0x0000000400000000UL
+
+static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm)
+{
+ irqreturn_t ret = IRQ_NONE;
+ u64 csr, csr_error_bits;
+ u16 stat, *addr;
+
+ csr = upa_readq(pbm->pci_csr);
+ csr_error_bits = csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
+ if (csr_error_bits) {
+ /* Clear the errors. */
+ upa_writeq(csr, pbm->pci_csr);
+
+ /* Log 'em. */
+ if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
+ printk(KERN_ERR "%s: PCI streaming byte hole "
+ "error asserted.\n", pbm->name);
+ if (csr_error_bits & PSYCHO_PCICTRL_SERR)
+ printk(KERN_ERR "%s: PCI SERR signal asserted.\n",
+ pbm->name);
+ ret = IRQ_HANDLED;
+ }
+ addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PCI_STATUS);
+ pci_config_read16(addr, &stat);
+ if (stat & (PCI_STATUS_PARITY |
+ PCI_STATUS_SIG_TARGET_ABORT |
+ PCI_STATUS_REC_TARGET_ABORT |
+ PCI_STATUS_REC_MASTER_ABORT |
+ PCI_STATUS_SIG_SYSTEM_ERROR)) {
+ printk(KERN_ERR "%s: PCI bus error, PCI_STATUS[%04x]\n",
+ pbm->name, stat);
+ pci_config_write16(addr, 0xffff);
+ ret = IRQ_HANDLED;
+ }
+ return ret;
+}
+
+#define PSYCHO_PCIAFSR_PMA 0x8000000000000000UL
+#define PSYCHO_PCIAFSR_PTA 0x4000000000000000UL
+#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000UL
+#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000UL
+#define PSYCHO_PCIAFSR_SMA 0x0800000000000000UL
+#define PSYCHO_PCIAFSR_STA 0x0400000000000000UL
+#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000UL
+#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000UL
+#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000UL
+#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000UL
+#define PSYCHO_PCIAFSR_BLK 0x0000000080000000UL
+#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000UL
+#define PSYCHO_PCIAFSR_MID 0x000000003e000000UL
+#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffffUL
+
+irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
+{
+ struct pci_pbm_info *pbm = dev_id;
+ u64 afsr, afar, error_bits;
+ int reported;
+
+ afsr = upa_readq(pbm->pci_afsr);
+ afar = upa_readq(pbm->pci_afar);
+ error_bits = afsr &
+ (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
+ PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
+ PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
+ PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
+ if (!error_bits)
+ return psycho_pcierr_intr_other(pbm);
+ upa_writeq(error_bits, pbm->pci_afsr);
+ printk(KERN_ERR "%s: PCI Error, primary error type[%s]\n",
+ pbm->name,
+ (((error_bits & PSYCHO_PCIAFSR_PMA) ?
+ "Master Abort" :
+ ((error_bits & PSYCHO_PCIAFSR_PTA) ?
+ "Target Abort" :
+ ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
+ "Excessive Retries" :
+ ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
+ "Parity Error" : "???"))))));
+ printk(KERN_ERR "%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
+ pbm->name,
+ (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
+ (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
+ (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
+ printk(KERN_ERR "%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+ printk(KERN_ERR "%s: PCI Secondary errors [", pbm->name);
+ reported = 0;
+ if (afsr & PSYCHO_PCIAFSR_SMA) {
+ reported++;
+ printk("(Master Abort)");
+ }
+ if (afsr & PSYCHO_PCIAFSR_STA) {
+ reported++;
+ printk("(Target Abort)");
+ }
+ if (afsr & PSYCHO_PCIAFSR_SRTRY) {
+ reported++;
+ printk("(Excessive Retries)");
+ }
+ if (afsr & PSYCHO_PCIAFSR_SPERR) {
+ reported++;
+ printk("(Parity Error)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
+ psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
+ pci_scan_for_target_abort(pbm, pbm->pci_bus);
+ }
+ if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
+ pci_scan_for_master_abort(pbm, pbm->pci_bus);
+
+ if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
+ pci_scan_for_parity_error(pbm, pbm->pci_bus);
+
+ return IRQ_HANDLED;
+}
+
+static void psycho_iommu_flush(struct pci_pbm_info *pbm)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ unsigned long off = i * 8;
+
+ upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_TAG + off);
+ upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_DATA + off);
+ }
+}
+
+#define PSYCHO_IOMMU_CONTROL 0x0200UL
+#define PSYCHO_IOMMU_CTRL_TSBSZ 0x0000000000070000UL
+#define PSYCHO_IOMMU_TSBSZ_1K 0x0000000000000000UL
+#define PSYCHO_IOMMU_TSBSZ_2K 0x0000000000010000UL
+#define PSYCHO_IOMMU_TSBSZ_4K 0x0000000000020000UL
+#define PSYCHO_IOMMU_TSBSZ_8K 0x0000000000030000UL
+#define PSYCHO_IOMMU_TSBSZ_16K 0x0000000000040000UL
+#define PSYCHO_IOMMU_TSBSZ_32K 0x0000000000050000UL
+#define PSYCHO_IOMMU_TSBSZ_64K 0x0000000000060000UL
+#define PSYCHO_IOMMU_TSBSZ_128K 0x0000000000070000UL
+#define PSYCHO_IOMMU_CTRL_TBWSZ 0x0000000000000004UL
+#define PSYCHO_IOMMU_CTRL_DENAB 0x0000000000000002UL
+#define PSYCHO_IOMMU_CTRL_ENAB 0x0000000000000001UL
+#define PSYCHO_IOMMU_FLUSH 0x0210UL
+#define PSYCHO_IOMMU_TSBBASE 0x0208UL
+
+int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+ u32 dvma_offset, u32 dma_mask,
+ unsigned long write_complete_offset)
+{
+ struct iommu *iommu = pbm->iommu;
+ u64 control;
+ int err;
+
+ iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
+ iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
+ iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
+ iommu->iommu_tags = pbm->controller_regs + PSYCHO_IOMMU_TAG;
+ iommu->write_complete_reg = (pbm->controller_regs +
+ write_complete_offset);
+
+ iommu->iommu_ctxflush = 0;
+
+ control = upa_readq(iommu->iommu_control);
+ control |= PSYCHO_IOMMU_CTRL_DENAB;
+ upa_writeq(control, iommu->iommu_control);
+
+ psycho_iommu_flush(pbm);
+
+ /* Leave diag mode enabled for full-flushing done in pci_iommu.c */
+ err = iommu_table_init(iommu, tsbsize * 1024 * 8,
+ dvma_offset, dma_mask, pbm->numa_node);
+ if (err)
+ return err;
+
+ upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
+
+ control = upa_readq(iommu->iommu_control);
+ control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
+ control |= PSYCHO_IOMMU_CTRL_ENAB;
+
+ switch (tsbsize) {
+ case 64:
+ control |= PSYCHO_IOMMU_TSBSZ_64K;
+ break;
+ case 128:
+ control |= PSYCHO_IOMMU_TSBSZ_128K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ upa_writeq(control, iommu->iommu_control);
+
+ return 0;
+
+}
+
+void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct of_device *op,
+ const char *chip_name, int chip_type)
+{
+ struct device_node *dp = op->node;
+
+ pbm->name = dp->full_name;
+ pbm->numa_node = -1;
+ pbm->chip_type = chip_type;
+ pbm->chip_version = of_getintprop_default(dp, "version#", 0);
+ pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
+ pbm->op = op;
+ pbm->pci_ops = &sun4u_pci_ops;
+ pbm->config_space_reg_bits = 8;
+ pbm->index = pci_num_pbms++;
+ pci_get_pbm_props(pbm);
+ pci_determine_mem_io_space(pbm);
+
+ printk(KERN_INFO "%s: %s PCI Bus Module ver[%x:%x]\n",
+ pbm->name, chip_name,
+ pbm->chip_version, pbm->chip_revision);
+}
diff --git a/arch/sparc64/kernel/psycho_common.h b/arch/sparc64/kernel/psycho_common.h
new file mode 100644
index 00000000000..092c278ef28
--- /dev/null
+++ b/arch/sparc64/kernel/psycho_common.h
@@ -0,0 +1,48 @@
+#ifndef _PSYCHO_COMMON_H
+#define _PSYCHO_COMMON_H
+
+/* U2P Programmer's Manual, page 13-55, configuration space
+ * address format:
+ *
+ * 32 24 23 16 15 11 10 8 7 2 1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define PSYCHO_CONFIG_BASE(PBM) \
+ ((PBM)->config_space | (1UL << 24))
+#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \
+ (((unsigned long)(BUS) << 16) | \
+ ((unsigned long)(DEVFN) << 8) | \
+ ((unsigned long)(REG)))
+
+static inline void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
+ unsigned char bus,
+ unsigned int devfn,
+ int where)
+{
+ return (void *)
+ (PSYCHO_CONFIG_BASE(pbm) |
+ PSYCHO_CONFIG_ENCODE(bus, devfn, where));
+}
+
+enum psycho_error_type {
+ UE_ERR, CE_ERR, PCI_ERR
+};
+
+extern void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+ unsigned long afsr,
+ unsigned long afar,
+ enum psycho_error_type type);
+
+extern irqreturn_t psycho_pcierr_intr(int irq, void *dev_id);
+
+extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+ u32 dvma_offset, u32 dma_mask,
+ unsigned long write_complete_offset);
+
+extern void psycho_pbm_init_common(struct pci_pbm_info *pbm,
+ struct of_device *op,
+ const char *chip_name, int chip_type);
+
+#endif /* _PSYCHO_COMMON_H */
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 10306e476e3..f43adbc773c 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -1050,31 +1050,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return ret;
}
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{
int ret = 0;
/* do the secure computing check first */
secure_computing(regs->u_regs[UREG_G1]);
- if (unlikely(current->audit_context) && syscall_exit_p) {
- unsigned long tstate = regs->tstate;
- int result = AUDITSC_SUCCESS;
-
- if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
- result = AUDITSC_FAILURE;
-
- audit_syscall_exit(result, regs->u_regs[UREG_I0]);
- }
-
- if (test_thread_flag(TIF_SYSCALL_TRACE)) {
- if (syscall_exit_p)
- tracehook_report_syscall_exit(regs, 0);
- else
- ret = tracehook_report_syscall_entry(regs);
- }
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ ret = tracehook_report_syscall_entry(regs);
- if (unlikely(current->audit_context) && !syscall_exit_p && !ret)
+ if (unlikely(current->audit_context) && !ret)
audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
AUDIT_ARCH_SPARC :
AUDIT_ARCH_SPARC64),
@@ -1086,3 +1072,19 @@ asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
return ret;
}
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+ if (unlikely(current->audit_context)) {
+ unsigned long tstate = regs->tstate;
+ int result = AUDITSC_SUCCESS;
+
+ if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+ result = AUDITSC_FAILURE;
+
+ audit_syscall_exit(result, regs->u_regs[UREG_I0]);
+ }
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, 0);
+}
diff --git a/arch/sparc64/kernel/reboot.c b/arch/sparc64/kernel/reboot.c
new file mode 100644
index 00000000000..ef89d3d6974
--- /dev/null
+++ b/arch/sparc64/kernel/reboot.c
@@ -0,0 +1,53 @@
+/* reboot.c: reboot/shutdown/halt/poweroff handling
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <asm/system.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+
+/* sysctl - toggle power-off restriction for serial console
+ * systems in machine_power_off()
+ */
+int scons_pwroff = 1;
+
+/* This isn't actually used, it exists merely to satisfy the
+ * reference in kernel/sys.c
+ */
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_power_off(void)
+{
+ if (strcmp(of_console_device->type, "serial") || scons_pwroff)
+ prom_halt_power_off();
+
+ prom_halt();
+}
+
+void machine_halt(void)
+{
+ prom_halt();
+ panic("Halt failed!");
+}
+
+void machine_restart(char *cmd)
+{
+ char *p;
+
+ p = strchr(reboot_command, '\n');
+ if (p)
+ *p = 0;
+ if (cmd)
+ prom_reboot(cmd);
+ if (*reboot_command)
+ prom_reboot(reboot_command);
+ prom_reboot("");
+ panic("Reboot failed!");
+}
+
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index e33a8a660e9..2ead310066d 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -11,15 +11,17 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/page.h>
-#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/upa.h>
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/prom.h>
+#include <asm/oplib.h>
#include <asm/starfire.h>
#include "iommu_common.h"
@@ -52,13 +54,23 @@
#define STRBUF_TAG_VALID 0x02UL
/* Enable 64-bit DVMA mode for the given device. */
-void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
+void sbus_set_sbus64(struct device *dev, int bursts)
{
- struct iommu *iommu = sdev->ofdev.dev.archdata.iommu;
- int slot = sdev->slot;
+ struct iommu *iommu = dev->archdata.iommu;
+ struct of_device *op = to_of_device(dev);
+ const struct linux_prom_registers *regs;
unsigned long cfg_reg;
+ int slot;
u64 val;
+ regs = of_get_property(op->node, "reg", NULL);
+ if (!regs) {
+ printk(KERN_ERR "sbus_set_sbus64: Cannot find regs for %s\n",
+ op->node->full_name);
+ return;
+ }
+ slot = regs->which_io;
+
cfg_reg = iommu->write_complete_reg;
switch (slot) {
case 0:
@@ -191,10 +203,9 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
return imap + diff;
}
-unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino)
{
- struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long imap, iclr;
int sbus_level = 0;
@@ -255,12 +266,12 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
#define SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
{
- struct sbus_bus *sbus = dev_id;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct of_device *op = dev_id;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
unsigned long afsr, afar, error_bits;
- int reported;
+ int reported, portid;
afsr_reg = reg_base + SYSIO_UE_AFSR;
afar_reg = reg_base + SYSIO_UE_AFAR;
@@ -275,9 +286,11 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR);
upa_writeq(error_bits, afsr_reg);
+ portid = of_getintprop_default(op->node, "portid", -1);
+
/* Log the error. */
printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n",
- sbus->portid,
+ portid,
(((error_bits & SYSIO_UEAFSR_PPIO) ?
"PIO" :
((error_bits & SYSIO_UEAFSR_PDRD) ?
@@ -285,12 +298,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
((error_bits & SYSIO_UEAFSR_PDWR) ?
"DVMA Write" : "???")))));
printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n",
- sbus->portid,
+ portid,
(afsr & SYSIO_UEAFSR_DOFF) >> 45UL,
(afsr & SYSIO_UEAFSR_SIZE) >> 42UL,
(afsr & SYSIO_UEAFSR_MID) >> 37UL);
- printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
- printk("SYSIO[%x]: Secondary UE errors [", sbus->portid);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+ printk("SYSIO[%x]: Secondary UE errors [", portid);
reported = 0;
if (afsr & SYSIO_UEAFSR_SPIO) {
reported++;
@@ -327,12 +340,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
#define SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
{
- struct sbus_bus *sbus = dev_id;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct of_device *op = dev_id;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
unsigned long afsr, afar, error_bits;
- int reported;
+ int reported, portid;
afsr_reg = reg_base + SYSIO_CE_AFSR;
afar_reg = reg_base + SYSIO_CE_AFAR;
@@ -347,8 +360,10 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR);
upa_writeq(error_bits, afsr_reg);
+ portid = of_getintprop_default(op->node, "portid", -1);
+
printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n",
- sbus->portid,
+ portid,
(((error_bits & SYSIO_CEAFSR_PPIO) ?
"PIO" :
((error_bits & SYSIO_CEAFSR_PDRD) ?
@@ -360,14 +375,14 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
* XXX UDB CE trap handler does... -DaveM
*/
printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n",
- sbus->portid,
+ portid,
(afsr & SYSIO_CEAFSR_DOFF) >> 45UL,
(afsr & SYSIO_CEAFSR_ESYND) >> 48UL,
(afsr & SYSIO_CEAFSR_SIZE) >> 42UL,
(afsr & SYSIO_CEAFSR_MID) >> 37UL);
- printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
- printk("SYSIO[%x]: Secondary CE errors [", sbus->portid);
+ printk("SYSIO[%x]: Secondary CE errors [", portid);
reported = 0;
if (afsr & SYSIO_CEAFSR_SPIO) {
reported++;
@@ -404,11 +419,11 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
#define SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved */
static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
{
- struct sbus_bus *sbus = dev_id;
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct of_device *op = dev_id;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long afsr_reg, afar_reg, reg_base;
unsigned long afsr, afar, error_bits;
- int reported;
+ int reported, portid;
reg_base = iommu->write_complete_reg - 0x2000UL;
afsr_reg = reg_base + SYSIO_SBUS_AFSR;
@@ -423,9 +438,11 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR);
upa_writeq(error_bits, afsr_reg);
+ portid = of_getintprop_default(op->node, "portid", -1);
+
/* Log the error. */
printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n",
- sbus->portid,
+ portid,
(((error_bits & SYSIO_SBAFSR_PLE) ?
"Late PIO Error" :
((error_bits & SYSIO_SBAFSR_PTO) ?
@@ -434,11 +451,11 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
"Error Ack" : "???")))),
(afsr & SYSIO_SBAFSR_RD) ? 1 : 0);
printk("SYSIO[%x]: size[%lx] MID[%lx]\n",
- sbus->portid,
+ portid,
(afsr & SYSIO_SBAFSR_SIZE) >> 42UL,
(afsr & SYSIO_SBAFSR_MID) >> 37UL);
- printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
- printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+ printk("SYSIO[%x]: Secondary SBUS errors [", portid);
reported = 0;
if (afsr & SYSIO_SBAFSR_SLE) {
reported++;
@@ -470,34 +487,37 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
#define SYSIO_CE_INO 0x35
#define SYSIO_SBUSERR_INO 0x36
-static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
+static void __init sysio_register_error_handlers(struct of_device *op)
{
- struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+ struct iommu *iommu = op->dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned int irq;
u64 control;
+ int portid;
+
+ portid = of_getintprop_default(op->node, "portid", -1);
- irq = sbus_build_irq(sbus, SYSIO_UE_INO);
+ irq = sbus_build_irq(op, SYSIO_UE_INO);
if (request_irq(irq, sysio_ue_handler, 0,
- "SYSIO_UE", sbus) < 0) {
+ "SYSIO_UE", op) < 0) {
prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
- sbus->portid);
+ portid);
prom_halt();
}
- irq = sbus_build_irq(sbus, SYSIO_CE_INO);
+ irq = sbus_build_irq(op, SYSIO_CE_INO);
if (request_irq(irq, sysio_ce_handler, 0,
- "SYSIO_CE", sbus) < 0) {
+ "SYSIO_CE", op) < 0) {
prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
- sbus->portid);
+ portid);
prom_halt();
}
- irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
+ irq = sbus_build_irq(op, SYSIO_SBUSERR_INO);
if (request_irq(irq, sysio_sbus_error_handler, 0,
- "SYSIO_SBERR", sbus) < 0) {
+ "SYSIO_SBERR", op) < 0) {
prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
- sbus->portid);
+ portid);
prom_halt();
}
@@ -513,19 +533,15 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
}
/* Boot time initialization. */
-static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
{
const struct linux_prom64_registers *pr;
- struct device_node *dp;
+ struct device_node *dp = op->node;
struct iommu *iommu;
struct strbuf *strbuf;
unsigned long regs, reg_base;
+ int i, portid;
u64 control;
- int i;
-
- dp = of_find_node_by_phandle(__node);
-
- sbus->portid = of_getintprop_default(dp, "upa-portid", -1);
pr = of_get_property(dp, "reg", NULL);
if (!pr) {
@@ -542,9 +558,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
if (!strbuf)
goto fatal_memory_error;
- sbus->ofdev.dev.archdata.iommu = iommu;
- sbus->ofdev.dev.archdata.stc = strbuf;
- sbus->ofdev.dev.archdata.numa_node = -1;
+ op->dev.archdata.iommu = iommu;
+ op->dev.archdata.stc = strbuf;
+ op->dev.archdata.numa_node = -1;
reg_base = regs + SYSIO_IOMMUREG_BASE;
iommu->iommu_control = reg_base + IOMMU_CONTROL;
@@ -572,8 +588,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
*/
iommu->write_complete_reg = regs + 0x2000UL;
- printk("SYSIO: UPA portID %x, at %016lx\n",
- sbus->portid, regs);
+ portid = of_getintprop_default(op->node, "portid", -1);
+ printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n",
+ portid, regs);
/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1))
@@ -631,56 +648,27 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
/* Now some Xfire specific grot... */
if (this_is_starfire)
- starfire_hookup(sbus->portid);
+ starfire_hookup(portid);
- sysio_register_error_handlers(sbus);
+ sysio_register_error_handlers(op);
return;
fatal_memory_error:
prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
}
-void sbus_fill_device_irq(struct sbus_dev *sdev)
+static int __init sbus_init(void)
{
- struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
- const struct linux_prom_irqs *irqs;
-
- irqs = of_get_property(dp, "interrupts", NULL);
- if (!irqs) {
- sdev->irqs[0] = 0;
- sdev->num_irqs = 0;
- } else {
- unsigned int pri = irqs[0].pri;
+ struct device_node *dp;
- sdev->num_irqs = 1;
- if (pri < 0x20)
- pri += sdev->slot * 8;
+ for_each_node_by_name(dp, "sbus") {
+ struct of_device *op = of_find_device_by_node(dp);
- sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
+ sbus_iommu_init(op);
+ of_propagate_archdata(op);
}
-}
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
-}
-
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
- sbus_iommu_init(dp->node, sbus);
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
-}
-
-int __init sbus_arch_preinit(void)
-{
return 0;
}
-void __init sbus_arch_postinit(void)
-{
- extern void firetruck_init(void);
-
- firetruck_init();
-}
+subsys_initcall(sbus_init);
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 2be166c544c..e5627118e61 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -21,6 +21,7 @@
#include <linux/jiffies.h>
#include <linux/profile.h>
#include <linux/lmb.h>
+#include <linux/cpu.h>
#include <asm/head.h>
#include <asm/ptrace.h>
@@ -115,6 +116,9 @@ void __cpuinit smp_callin(void)
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
+ /* inform the notifiers about the new cpu */
+ notify_cpu_starting(cpuid);
+
while (!cpu_isset(cpuid, smp_commenced_mask))
rmb();
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 0804f71df6c..30bba8b0a3b 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -36,7 +36,6 @@
#include <asm/elf.h>
#include <asm/head.h>
#include <asm/smp.h>
-#include <asm/mostek.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
@@ -44,12 +43,8 @@
#include <asm/pgalloc.h>
#include <asm/cacheflush.h>
#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
#include <asm/dma.h>
#endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
#include <asm/ns87303.h>
#include <asm/timer.h>
#include <asm/cpudata.h>
@@ -68,7 +63,6 @@ extern void *__memscan_zero(void *, size_t);
extern void *__memscan_generic(void *, int, size_t);
extern int __memcmp(const void *, const void *, __kernel_size_t);
extern __kernel_size_t strlen(const char *);
-extern void syscall_trace(struct pt_regs *, int);
extern void sys_sigsuspend(void);
extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
@@ -154,26 +148,12 @@ EXPORT_SYMBOL(flush_dcache_page);
EXPORT_SYMBOL(__flush_dcache_range);
#endif
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
#ifdef CONFIG_SUN_AUXIO
EXPORT_SYMBOL(auxio_set_led);
EXPORT_SYMBOL(auxio_set_lte);
#endif
#ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
#endif
EXPORT_SYMBOL(outsb);
EXPORT_SYMBOL(outsw);
@@ -182,7 +162,6 @@ EXPORT_SYMBOL(insb);
EXPORT_SYMBOL(insw);
EXPORT_SYMBOL(insl);
#ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
EXPORT_SYMBOL(pci_map_single);
@@ -300,3 +279,5 @@ EXPORT_SYMBOL(xor_niagara_2);
EXPORT_SYMBOL(xor_niagara_3);
EXPORT_SYMBOL(xor_niagara_4);
EXPORT_SYMBOL(xor_niagara_5);
+
+EXPORT_SYMBOL_GPL(real_hard_smp_processor_id);
diff --git a/arch/sparc64/kernel/sstate.c b/arch/sparc64/kernel/sstate.c
index 5b6e75b7f05..8cdbe5946b4 100644
--- a/arch/sparc64/kernel/sstate.c
+++ b/arch/sparc64/kernel/sstate.c
@@ -1,14 +1,15 @@
/* sstate.c: System soft state support.
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
#include <linux/notifier.h>
+#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/hypervisor.h>
-#include <asm/sstate.h>
+#include <asm/spitfire.h>
#include <asm/oplib.h>
#include <asm/head.h>
#include <asm/io.h>
@@ -50,31 +51,34 @@ static const char rebooting_msg[32] __attribute__((aligned(32))) =
static const char panicing_msg[32] __attribute__((aligned(32))) =
"Linux panicing";
-void sstate_booting(void)
+static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
-}
+ const char *msg;
-void sstate_running(void)
-{
- do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
-}
+ switch (type) {
+ case SYS_DOWN:
+ default:
+ msg = rebooting_msg;
+ break;
-void sstate_halt(void)
-{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg);
-}
+ case SYS_HALT:
+ msg = halting_msg;
+ break;
-void sstate_poweroff(void)
-{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg);
-}
+ case SYS_POWER_OFF:
+ msg = poweroff_msg;
+ break;
+ }
-void sstate_reboot(void)
-{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg);
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, msg);
+
+ return NOTIFY_OK;
}
+static struct notifier_block sstate_reboot_notifier = {
+ .notifier_call = sstate_reboot_call,
+};
+
static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
{
do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
@@ -87,18 +91,37 @@ static struct notifier_block sstate_panic_block = {
.priority = INT_MAX,
};
-void __init sun4v_sstate_init(void)
+static int __init sstate_init(void)
{
unsigned long major, minor;
+ if (tlb_type != hypervisor)
+ return 0;
+
major = 1;
minor = 0;
if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor))
- return;
+ return 0;
hv_supports_soft_state = 1;
prom_sun4v_guest_soft_state();
+
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
+
atomic_notifier_chain_register(&panic_notifier_list,
&sstate_panic_block);
+ register_reboot_notifier(&sstate_reboot_notifier);
+
+ return 0;
}
+
+core_initcall(sstate_init);
+
+static int __init sstate_running(void)
+{
+ do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
+ return 0;
+}
+
+late_initcall(sstate_running);
diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
index 7461581b3bb..060d0f3a615 100644
--- a/arch/sparc64/kernel/starfire.c
+++ b/arch/sparc64/kernel/starfire.c
@@ -28,11 +28,6 @@ void check_if_starfire(void)
this_is_starfire = 1;
}
-void starfire_cpu_setup(void)
-{
- /* Currently, nothing to do. */
-}
-
int starfire_hard_smp_processor_id(void)
{
return upa_readl(0x1fff40000d0UL);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 3d118531baf..3320c9d0075 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -575,14 +575,6 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}
-/* These are here just in case some old sparc32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- return -ERESTARTNOHAND;
-}
-
asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
char __user *ubuf,
compat_size_t count,
diff --git a/arch/sparc64/kernel/syscalls.S b/arch/sparc64/kernel/syscalls.S
index a2f24270ed8..7a6786a7136 100644
--- a/arch/sparc64/kernel/syscalls.S
+++ b/arch/sparc64/kernel/syscalls.S
@@ -65,9 +65,8 @@ sys32_rt_sigreturn:
andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
be,pt %icc, rtrap
nop
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- mov 1, %o1
+ call syscall_trace_leave
+ add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
nop
@@ -159,9 +158,8 @@ linux_sparc_ni_syscall:
or %l7, %lo(sys_ni_syscall), %l7
linux_syscall_trace32:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- clr %o1
+ call syscall_trace_enter
+ add %sp, PTREGS_OFF, %o0
brnz,pn %o0, 3f
mov -ENOSYS, %o0
srl %i0, 0, %o0
@@ -172,9 +170,8 @@ linux_syscall_trace32:
srl %i3, 0, %o3
linux_syscall_trace:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- clr %o1
+ call syscall_trace_enter
+ add %sp, PTREGS_OFF, %o0
brnz,pn %o0, 3f
mov -ENOSYS, %o0
mov %i0, %o0
@@ -275,9 +272,8 @@ ret_sys_call:
b,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
linux_syscall_trace2:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- mov 1, %o1
+ call syscall_trace_leave
+ add %sp, PTREGS_OFF, %o0
stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
ba,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 0fdbf3ba956..5daee4b04dd 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -23,7 +23,7 @@ sys_call_table32:
/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod
/*15*/ .word sys_chmod, sys_lchown16, sparc_brk, sys32_perfctr, sys32_lseek
/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
-/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
+/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause
/*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice
.word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile
/*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index cc16fdcf98a..80d71a5ce1e 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -30,13 +30,14 @@
#include <linux/percpu.h>
#include <linux/miscdevice.h>
#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
#include <linux/kernel_stat.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <asm/oplib.h>
-#include <asm/mostek.h>
#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -50,18 +51,7 @@
#include "entry.h"
-DEFINE_SPINLOCK(mostek_lock);
DEFINE_SPINLOCK(rtc_lock);
-void __iomem *mstk48t02_regs = NULL;
-#ifdef CONFIG_PCI
-unsigned long ds1287_regs = 0UL;
-static void __iomem *bq4802_regs;
-#endif
-
-static void __iomem *mstk48t08_regs;
-static void __iomem *mstk48t59_regs;
-
-static int set_rtc_mmss(unsigned long);
#define TICK_PRIV_BIT (1UL << 63)
#define TICKCMP_IRQ_BIT (1UL << 63)
@@ -405,313 +395,167 @@ static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
int update_persistent_clock(struct timespec now)
{
- return set_rtc_mmss(now.tv_sec);
-}
+ struct rtc_device *rtc = rtc_class_open("rtc0");
+ int err = -1;
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __init kick_start_clock(void)
-{
- void __iomem *regs = mstk48t02_regs;
- u8 sec, tmp;
- int i, count;
-
- prom_printf("CLOCK: Clock was stopped. Kick start ");
-
- spin_lock_irq(&mostek_lock);
-
- /* Turn on the kick start bit to start the oscillator. */
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
- tmp = mostek_read(regs + MOSTEK_SEC);
- tmp &= ~MSTK_STOP;
- mostek_write(regs + MOSTEK_SEC, tmp);
- tmp = mostek_read(regs + MOSTEK_HOUR);
- tmp |= MSTK_KICK_START;
- mostek_write(regs + MOSTEK_HOUR, tmp);
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
-
- /* Delay to allow the clock oscillator to start. */
- sec = MSTK_REG_SEC(regs);
- for (i = 0; i < 3; i++) {
- while (sec == MSTK_REG_SEC(regs))
- for (count = 0; count < 100000; count++)
- /* nothing */ ;
- prom_printf(".");
- sec = MSTK_REG_SEC(regs);
- }
- prom_printf("\n");
-
- spin_lock_irq(&mostek_lock);
-
- /* Turn off kick start and set a "valid" time and date. */
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
- tmp = mostek_read(regs + MOSTEK_HOUR);
- tmp &= ~MSTK_KICK_START;
- mostek_write(regs + MOSTEK_HOUR, tmp);
- MSTK_SET_REG_SEC(regs,0);
- MSTK_SET_REG_MIN(regs,0);
- MSTK_SET_REG_HOUR(regs,0);
- MSTK_SET_REG_DOW(regs,5);
- MSTK_SET_REG_DOM(regs,1);
- MSTK_SET_REG_MONTH(regs,8);
- MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
-
- /* Ensure the kick start bit is off. If it isn't, turn it off. */
- while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) {
- prom_printf("CLOCK: Kick start still on!\n");
-
- spin_lock_irq(&mostek_lock);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- tmp = mostek_read(regs + MOSTEK_HOUR);
- tmp &= ~MSTK_KICK_START;
- mostek_write(regs + MOSTEK_HOUR, tmp);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
+ if (rtc) {
+ err = rtc_set_mmss(rtc, now.tv_sec);
+ rtc_class_close(rtc);
}
- prom_printf("CLOCK: Kick start procedure successful.\n");
+ return err;
}
-/* Return nonzero if the clock chip battery is low. */
-static int __init has_low_battery(void)
-{
- void __iomem *regs = mstk48t02_regs;
- u8 data1, data2;
-
- spin_lock_irq(&mostek_lock);
+unsigned long cmos_regs;
+EXPORT_SYMBOL(cmos_regs);
- data1 = mostek_read(regs + MOSTEK_EEPROM); /* Read some data. */
- mostek_write(regs + MOSTEK_EEPROM, ~data1); /* Write back the complement. */
- data2 = mostek_read(regs + MOSTEK_EEPROM); /* Read back the complement. */
- mostek_write(regs + MOSTEK_EEPROM, data1); /* Restore original value. */
+static struct resource rtc_cmos_resource;
- spin_unlock_irq(&mostek_lock);
-
- return (data1 == data2); /* Was the write blocked? */
-}
+static struct platform_device rtc_cmos_device = {
+ .name = "rtc_cmos",
+ .id = -1,
+ .resource = &rtc_cmos_resource,
+ .num_resources = 1,
+};
-static void __init mostek_set_system_time(void __iomem *mregs)
+static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match)
{
- unsigned int year, mon, day, hour, min, sec;
- u8 tmp;
-
- spin_lock_irq(&mostek_lock);
+ struct resource *r;
- /* Traditional Mostek chip. */
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
+ printk(KERN_INFO "%s: RTC regs at 0x%lx\n",
+ op->node->full_name, op->resource[0].start);
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
+ /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons
+ * up a fake resource so that the probe works for all cases.
+ * When the RTC is behind an ISA bus it will have IORESOURCE_IO
+ * already, whereas when it's behind EBUS is will be IORESOURCE_MEM.
+ */
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
+ r = &rtc_cmos_resource;
+ r->flags = IORESOURCE_IO;
+ r->name = op->resource[0].name;
+ r->start = op->resource[0].start;
+ r->end = op->resource[0].end;
- spin_unlock_irq(&mostek_lock);
+ cmos_regs = op->resource[0].start;
+ return platform_device_register(&rtc_cmos_device);
}
-/* Probe for the real time clock chip. */
-static void __init set_system_time(void)
-{
- unsigned int year, mon, day, hour, min, sec;
- void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
- unsigned long dregs = ds1287_regs;
- void __iomem *bregs = bq4802_regs;
-#else
- unsigned long dregs = 0UL;
- void __iomem *bregs = 0UL;
-#endif
-
- if (!mregs && !dregs && !bregs) {
- prom_printf("Something wrong, clock regs not mapped yet.\n");
- prom_halt();
- }
-
- if (mregs) {
- mostek_set_system_time(mregs);
- return;
- }
-
- if (bregs) {
- unsigned char val = readb(bregs + 0x0e);
- unsigned int century;
+static struct of_device_id __initdata rtc_match[] = {
+ {
+ .name = "rtc",
+ .compatible = "m5819",
+ },
+ {
+ .name = "rtc",
+ .compatible = "isa-m5819p",
+ },
+ {
+ .name = "rtc",
+ .compatible = "isa-m5823p",
+ },
+ {
+ .name = "rtc",
+ .compatible = "ds1287",
+ },
+ {},
+};
- /* BQ4802 RTC chip. */
+static struct of_platform_driver rtc_driver = {
+ .match_table = rtc_match,
+ .probe = rtc_probe,
+ .driver = {
+ .name = "rtc",
+ },
+};
- writeb(val | 0x08, bregs + 0x0e);
+static struct platform_device rtc_bq4802_device = {
+ .name = "rtc-bq4802",
+ .id = -1,
+ .num_resources = 1,
+};
- sec = readb(bregs + 0x00);
- min = readb(bregs + 0x02);
- hour = readb(bregs + 0x04);
- day = readb(bregs + 0x06);
- mon = readb(bregs + 0x09);
- year = readb(bregs + 0x0a);
- century = readb(bregs + 0x0f);
+static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match)
+{
- writeb(val, bregs + 0x0e);
+ printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n",
+ op->node->full_name, op->resource[0].start);
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- BCD_TO_BIN(century);
+ rtc_bq4802_device.resource = &op->resource[0];
+ return platform_device_register(&rtc_bq4802_device);
+}
- year += (century * 100);
- } else {
- /* Dallas 12887 RTC chip. */
-
- do {
- sec = CMOS_READ(RTC_SECONDS);
- min = CMOS_READ(RTC_MINUTES);
- hour = CMOS_READ(RTC_HOURS);
- day = CMOS_READ(RTC_DAY_OF_MONTH);
- mon = CMOS_READ(RTC_MONTH);
- year = CMOS_READ(RTC_YEAR);
- } while (sec != CMOS_READ(RTC_SECONDS));
-
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- }
- if ((year += 1900) < 1970)
- year += 100;
- }
+static struct of_device_id __initdata bq4802_match[] = {
+ {
+ .name = "rtc",
+ .compatible = "bq4802",
+ },
+};
- xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
-}
+static struct of_platform_driver bq4802_driver = {
+ .match_table = bq4802_match,
+ .probe = bq4802_probe,
+ .driver = {
+ .name = "bq4802",
+ },
+};
-/* davem suggests we keep this within the 4M locked kernel image */
-static u32 starfire_get_time(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
{
- static char obp_gettod[32];
- static u32 unix_tod;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ void __iomem *regs;
+ unsigned char val;
- sprintf(obp_gettod, "h# %08x unix-gettod",
- (unsigned int) (long) &unix_tod);
- prom_feval(obp_gettod);
+ regs = (void __iomem *) pdev->resource[0].start;
+ val = readb(regs + ofs);
- return unix_tod;
+ /* the year 0 is 1968 */
+ if (ofs == pdata->offset + M48T59_YEAR) {
+ val += 0x68;
+ if ((val & 0xf) > 9)
+ val += 6;
+ }
+ return val;
}
-static int starfire_set_time(u32 val)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
{
- /* Do nothing, time is set using the service processor
- * console on this platform.
- */
- return 0;
-}
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ void __iomem *regs;
-static u32 hypervisor_get_time(void)
-{
- unsigned long ret, time;
- int retries = 10000;
-
-retry:
- ret = sun4v_tod_get(&time);
- if (ret == HV_EOK)
- return time;
- if (ret == HV_EWOULDBLOCK) {
- if (--retries > 0) {
- udelay(100);
- goto retry;
- }
- printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
- return 0;
+ regs = (void __iomem *) pdev->resource[0].start;
+ if (ofs == pdata->offset + M48T59_YEAR) {
+ if (val < 0x68)
+ val += 0x32;
+ else
+ val -= 0x68;
+ if ((val & 0xf) > 9)
+ val += 6;
+ if ((val & 0xf0) > 0x9A)
+ val += 0x60;
}
- printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
- return 0;
+ writeb(val, regs + ofs);
}
-static int hypervisor_set_time(u32 secs)
-{
- unsigned long ret;
- int retries = 10000;
-
-retry:
- ret = sun4v_tod_set(secs);
- if (ret == HV_EOK)
- return 0;
- if (ret == HV_EWOULDBLOCK) {
- if (--retries > 0) {
- udelay(100);
- goto retry;
- }
- printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
- return -EAGAIN;
- }
- printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
- return -EOPNOTSUPP;
-}
+static struct m48t59_plat_data m48t59_data = {
+ .read_byte = mostek_read_byte,
+ .write_byte = mostek_write_byte,
+};
-static int __init clock_model_matches(const char *model)
-{
- if (strcmp(model, "mk48t02") &&
- strcmp(model, "mk48t08") &&
- strcmp(model, "mk48t59") &&
- strcmp(model, "m5819") &&
- strcmp(model, "m5819p") &&
- strcmp(model, "m5823") &&
- strcmp(model, "ds1287") &&
- strcmp(model, "bq4802"))
- return 0;
-
- return 1;
-}
+static struct platform_device m48t59_rtc = {
+ .name = "rtc-m48t59",
+ .id = 0,
+ .num_resources = 1,
+ .dev = {
+ .platform_data = &m48t59_data,
+ },
+};
-static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->node;
- const char *model = of_get_property(dp, "model", NULL);
- const char *compat = of_get_property(dp, "compatible", NULL);
- unsigned long size, flags;
- void __iomem *regs;
-
- if (!model)
- model = compat;
-
- if (!model || !clock_model_matches(model))
- return -ENODEV;
/* On an Enterprise system there can be multiple mostek clocks.
* We should only match the one that is on the central FHC bus.
@@ -720,88 +564,51 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
strcmp(dp->parent->parent->name, "central") != 0)
return -ENODEV;
- size = (op->resource[0].end - op->resource[0].start) + 1;
- regs = of_ioremap(&op->resource[0], 0, size, "clock");
- if (!regs)
- return -ENOMEM;
-
-#ifdef CONFIG_PCI
- if (!strcmp(model, "ds1287") ||
- !strcmp(model, "m5819") ||
- !strcmp(model, "m5819p") ||
- !strcmp(model, "m5823")) {
- ds1287_regs = (unsigned long) regs;
- } else if (!strcmp(model, "bq4802")) {
- bq4802_regs = regs;
- } else
-#endif
- if (model[5] == '0' && model[6] == '2') {
- mstk48t02_regs = regs;
- } else if(model[5] == '0' && model[6] == '8') {
- mstk48t08_regs = regs;
- mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
- } else {
- mstk48t59_regs = regs;
- mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
- }
-
- printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);
-
- local_irq_save(flags);
-
- if (mstk48t02_regs != NULL) {
- /* Report a low battery voltage condition. */
- if (has_low_battery())
- prom_printf("NVRAM: Low battery voltage!\n");
-
- /* Kick start the clock if it is completely stopped. */
- if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
- kick_start_clock();
- }
-
- set_system_time();
-
- local_irq_restore(flags);
+ printk(KERN_INFO "%s: Mostek regs at 0x%lx\n",
+ dp->full_name, op->resource[0].start);
- return 0;
+ m48t59_rtc.resource = &op->resource[0];
+ return platform_device_register(&m48t59_rtc);
}
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata mostek_match[] = {
{
.name = "eeprom",
},
- {
- .name = "rtc",
- },
{},
};
-static struct of_platform_driver clock_driver = {
- .match_table = clock_match,
- .probe = clock_probe,
+static struct of_platform_driver mostek_driver = {
+ .match_table = mostek_match,
+ .probe = mostek_probe,
.driver = {
- .name = "clock",
+ .name = "mostek",
},
};
+static struct platform_device rtc_sun4v_device = {
+ .name = "rtc-sun4v",
+ .id = -1,
+};
+
+static struct platform_device rtc_starfire_device = {
+ .name = "rtc-starfire",
+ .id = -1,
+};
+
static int __init clock_init(void)
{
- if (this_is_starfire) {
- xtime.tv_sec = starfire_get_time();
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- return 0;
- }
- if (tlb_type == hypervisor) {
- xtime.tv_sec = hypervisor_get_time();
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- return 0;
- }
+ if (this_is_starfire)
+ return platform_device_register(&rtc_starfire_device);
+
+ if (tlb_type == hypervisor)
+ return platform_device_register(&rtc_sun4v_device);
+
+ (void) of_register_driver(&rtc_driver, &of_platform_bus_type);
+ (void) of_register_driver(&mostek_driver, &of_platform_bus_type);
+ (void) of_register_driver(&bq4802_driver, &of_platform_bus_type);
- return of_register_driver(&clock_driver, &of_platform_bus_type);
+ return 0;
}
/* Must be after subsys_initcall() so that busses are probed. Must
@@ -814,7 +621,7 @@ fs_initcall(clock_init);
static unsigned long sparc64_init_timers(void)
{
struct device_node *dp;
- unsigned long clock;
+ unsigned long freq;
dp = of_find_node_by_path("/");
if (tlb_type == spitfire) {
@@ -827,17 +634,17 @@ static unsigned long sparc64_init_timers(void)
if (manuf == 0x17 && impl == 0x13) {
/* Hummingbird, aka Ultra-IIe */
tick_ops = &hbtick_operations;
- clock = of_getintprop_default(dp, "stick-frequency", 0);
+ freq = of_getintprop_default(dp, "stick-frequency", 0);
} else {
tick_ops = &tick_operations;
- clock = local_cpu_data().clock_tick;
+ freq = local_cpu_data().clock_tick;
}
} else {
tick_ops = &stick_operations;
- clock = of_getintprop_default(dp, "stick-frequency", 0);
+ freq = of_getintprop_default(dp, "stick-frequency", 0);
}
- return clock;
+ return freq;
}
struct freq_table {
@@ -1029,16 +836,16 @@ EXPORT_SYMBOL(udelay);
void __init time_init(void)
{
- unsigned long clock = sparc64_init_timers();
+ unsigned long freq = sparc64_init_timers();
- tb_ticks_per_usec = clock / USEC_PER_SEC;
+ tb_ticks_per_usec = freq / USEC_PER_SEC;
timer_ticks_per_nsec_quotient =
- clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
+ clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT);
clocksource_tick.name = tick_ops->name;
clocksource_tick.mult =
- clocksource_hz2mult(clock,
+ clocksource_hz2mult(freq,
clocksource_tick.shift);
clocksource_tick.read = tick_ops->get_tick;
@@ -1049,7 +856,7 @@ void __init time_init(void)
sparc64_clockevent.name = tick_ops->name;
- setup_clockevent_multiplier(clock);
+ setup_clockevent_multiplier(freq);
sparc64_clockevent.max_delta_ns =
clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent);
@@ -1070,672 +877,8 @@ unsigned long long sched_clock(void)
>> SPARC64_NSEC_PER_CYC_SHIFT;
}
-static int set_rtc_mmss(unsigned long nowtime)
-{
- int real_seconds, real_minutes, chip_minutes;
- void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
- unsigned long dregs = ds1287_regs;
- void __iomem *bregs = bq4802_regs;
-#else
- unsigned long dregs = 0UL;
- void __iomem *bregs = 0UL;
-#endif
- unsigned long flags;
- u8 tmp;
-
- /*
- * Not having a register set can lead to trouble.
- * Also starfire doesn't have a tod clock.
- */
- if (!mregs && !dregs && !bregs)
- return -1;
-
- if (mregs) {
- spin_lock_irqsave(&mostek_lock, flags);
-
- /* Read the current RTC minutes. */
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
-
- chip_minutes = MSTK_REG_MIN(mregs);
-
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - chip_minutes) < 30) {
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(mregs + MOSTEK_CREG, tmp);
-
- MSTK_SET_REG_SEC(mregs,real_seconds);
- MSTK_SET_REG_MIN(mregs,real_minutes);
-
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(mregs + MOSTEK_CREG, tmp);
-
- spin_unlock_irqrestore(&mostek_lock, flags);
-
- return 0;
- } else {
- spin_unlock_irqrestore(&mostek_lock, flags);
-
- return -1;
- }
- } else if (bregs) {
- int retval = 0;
- unsigned char val = readb(bregs + 0x0e);
-
- /* BQ4802 RTC chip. */
-
- writeb(val | 0x08, bregs + 0x0e);
-
- chip_minutes = readb(bregs + 0x02);
- BCD_TO_BIN(chip_minutes);
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
- real_minutes += 30;
- real_minutes %= 60;
-
- if (abs(real_minutes - chip_minutes) < 30) {
- BIN_TO_BCD(real_seconds);
- BIN_TO_BCD(real_minutes);
- writeb(real_seconds, bregs + 0x00);
- writeb(real_minutes, bregs + 0x02);
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- chip_minutes, real_minutes);
- retval = -1;
- }
-
- writeb(val, bregs + 0x0e);
-
- return retval;
- } else {
- int retval = 0;
- unsigned char save_control, save_freq_select;
-
- /* Stolen from arch/i386/kernel/time.c, see there for
- * credits and descriptive comments.
- */
- spin_lock_irqsave(&rtc_lock, flags);
- save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
- CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
- CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
- chip_minutes = CMOS_READ(RTC_MINUTES);
- if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- BCD_TO_BIN(chip_minutes);
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
- real_minutes += 30;
- real_minutes %= 60;
-
- if (abs(real_minutes - chip_minutes) < 30) {
- if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BIN_TO_BCD(real_seconds);
- BIN_TO_BCD(real_minutes);
- }
- CMOS_WRITE(real_seconds,RTC_SECONDS);
- CMOS_WRITE(real_minutes,RTC_MINUTES);
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- chip_minutes, real_minutes);
- retval = -1;
- }
-
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return retval;
- }
-}
-
-#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
-static unsigned char mini_rtc_status; /* bitmapped status byte. */
-
-#define FEBRUARY 2
-#define STARTOFTIME 1970
-#define SECDAY 86400L
-#define SECYR (SECDAY * 365)
-#define leapyear(year) ((year) % 4 == 0 && \
- ((year) % 100 != 0 || (year) % 400 == 0))
-#define days_in_year(a) (leapyear(a) ? 366 : 365)
-#define days_in_month(a) (month_days[(a) - 1])
-
-static int month_days[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-/*
- * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
- */
-static void GregorianDay(struct rtc_time * tm)
-{
- int leapsToDate;
- int lastYear;
- int day;
- int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-
- lastYear = tm->tm_year - 1;
-
- /*
- * Number of leap corrections to apply up to end of last year
- */
- leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
-
- /*
- * This year is a leap year if it is divisible by 4 except when it is
- * divisible by 100 unless it is divisible by 400
- *
- * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
- */
- day = tm->tm_mon > 2 && leapyear(tm->tm_year);
-
- day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
- tm->tm_mday;
-
- tm->tm_wday = day % 7;
-}
-
-static void to_tm(int tim, struct rtc_time *tm)
-{
- register int i;
- register long hms, day;
-
- day = tim / SECDAY;
- hms = tim % SECDAY;
-
- /* Hours, minutes, seconds are easy */
- tm->tm_hour = hms / 3600;
- tm->tm_min = (hms % 3600) / 60;
- tm->tm_sec = (hms % 3600) % 60;
-
- /* Number of years in days */
- for (i = STARTOFTIME; day >= days_in_year(i); i++)
- day -= days_in_year(i);
- tm->tm_year = i;
-
- /* Number of months in days left */
- if (leapyear(tm->tm_year))
- days_in_month(FEBRUARY) = 29;
- for (i = 1; day >= days_in_month(i); i++)
- day -= days_in_month(i);
- days_in_month(FEBRUARY) = 28;
- tm->tm_mon = i;
-
- /* Days are what is left over (+1) from all that. */
- tm->tm_mday = day + 1;
-
- /*
- * Determine the day of week
- */
- GregorianDay(tm);
-}
-
-/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
- * aka Unix time. So we have to convert to/from rtc_time.
- */
-static void starfire_get_rtc_time(struct rtc_time *time)
-{
- u32 seconds = starfire_get_time();
-
- to_tm(seconds, time);
- time->tm_year -= 1900;
- time->tm_mon -= 1;
-}
-
-static int starfire_set_rtc_time(struct rtc_time *time)
-{
- u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
- time->tm_mday, time->tm_hour,
- time->tm_min, time->tm_sec);
-
- return starfire_set_time(seconds);
-}
-
-static void hypervisor_get_rtc_time(struct rtc_time *time)
-{
- u32 seconds = hypervisor_get_time();
-
- to_tm(seconds, time);
- time->tm_year -= 1900;
- time->tm_mon -= 1;
-}
-
-static int hypervisor_set_rtc_time(struct rtc_time *time)
-{
- u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
- time->tm_mday, time->tm_hour,
- time->tm_min, time->tm_sec);
-
- return hypervisor_set_time(seconds);
-}
-
-#ifdef CONFIG_PCI
-static void bq4802_get_rtc_time(struct rtc_time *time)
-{
- unsigned char val = readb(bq4802_regs + 0x0e);
- unsigned int century;
-
- writeb(val | 0x08, bq4802_regs + 0x0e);
-
- time->tm_sec = readb(bq4802_regs + 0x00);
- time->tm_min = readb(bq4802_regs + 0x02);
- time->tm_hour = readb(bq4802_regs + 0x04);
- time->tm_mday = readb(bq4802_regs + 0x06);
- time->tm_mon = readb(bq4802_regs + 0x09);
- time->tm_year = readb(bq4802_regs + 0x0a);
- time->tm_wday = readb(bq4802_regs + 0x08);
- century = readb(bq4802_regs + 0x0f);
-
- writeb(val, bq4802_regs + 0x0e);
-
- BCD_TO_BIN(time->tm_sec);
- BCD_TO_BIN(time->tm_min);
- BCD_TO_BIN(time->tm_hour);
- BCD_TO_BIN(time->tm_mday);
- BCD_TO_BIN(time->tm_mon);
- BCD_TO_BIN(time->tm_year);
- BCD_TO_BIN(time->tm_wday);
- BCD_TO_BIN(century);
-
- time->tm_year += (century * 100);
- time->tm_year -= 1900;
-
- time->tm_mon--;
-}
-
-static int bq4802_set_rtc_time(struct rtc_time *time)
-{
- unsigned char val = readb(bq4802_regs + 0x0e);
- unsigned char sec, min, hrs, day, mon, yrs, century;
- unsigned int year;
-
- year = time->tm_year + 1900;
- century = year / 100;
- yrs = year % 100;
-
- mon = time->tm_mon + 1; /* tm_mon starts at zero */
- day = time->tm_mday;
- hrs = time->tm_hour;
- min = time->tm_min;
- sec = time->tm_sec;
-
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hrs);
- BIN_TO_BCD(day);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(yrs);
- BIN_TO_BCD(century);
-
- writeb(val | 0x08, bq4802_regs + 0x0e);
-
- writeb(sec, bq4802_regs + 0x00);
- writeb(min, bq4802_regs + 0x02);
- writeb(hrs, bq4802_regs + 0x04);
- writeb(day, bq4802_regs + 0x06);
- writeb(mon, bq4802_regs + 0x09);
- writeb(yrs, bq4802_regs + 0x0a);
- writeb(century, bq4802_regs + 0x0f);
-
- writeb(val, bq4802_regs + 0x0e);
-
- return 0;
-}
-
-static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
-{
- unsigned char ctrl;
-
- rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
- rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
- rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
- rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
- rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
- rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
- rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
-
- ctrl = CMOS_READ(RTC_CONTROL);
- if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BCD_TO_BIN(rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_min);
- BCD_TO_BIN(rtc_tm->tm_hour);
- BCD_TO_BIN(rtc_tm->tm_mday);
- BCD_TO_BIN(rtc_tm->tm_mon);
- BCD_TO_BIN(rtc_tm->tm_year);
- BCD_TO_BIN(rtc_tm->tm_wday);
- }
-
- if (rtc_tm->tm_year <= 69)
- rtc_tm->tm_year += 100;
-
- rtc_tm->tm_mon--;
-}
-
-static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
-{
- unsigned char mon, day, hrs, min, sec;
- unsigned char save_control, save_freq_select;
- unsigned int yrs;
-
- yrs = rtc_tm->tm_year;
- mon = rtc_tm->tm_mon + 1;
- day = rtc_tm->tm_mday;
- hrs = rtc_tm->tm_hour;
- min = rtc_tm->tm_min;
- sec = rtc_tm->tm_sec;
-
- if (yrs >= 100)
- yrs -= 100;
-
- if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hrs);
- BIN_TO_BCD(day);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(yrs);
- }
-
- save_control = CMOS_READ(RTC_CONTROL);
- CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
- CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
- CMOS_WRITE(yrs, RTC_YEAR);
- CMOS_WRITE(mon, RTC_MONTH);
- CMOS_WRITE(day, RTC_DAY_OF_MONTH);
- CMOS_WRITE(hrs, RTC_HOURS);
- CMOS_WRITE(min, RTC_MINUTES);
- CMOS_WRITE(sec, RTC_SECONDS);
-
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
- return 0;
-}
-#endif /* CONFIG_PCI */
-
-static void mostek_get_rtc_time(struct rtc_time *rtc_tm)
-{
- void __iomem *regs = mstk48t02_regs;
- u8 tmp;
-
- spin_lock_irq(&mostek_lock);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- rtc_tm->tm_sec = MSTK_REG_SEC(regs);
- rtc_tm->tm_min = MSTK_REG_MIN(regs);
- rtc_tm->tm_hour = MSTK_REG_HOUR(regs);
- rtc_tm->tm_mday = MSTK_REG_DOM(regs);
- rtc_tm->tm_mon = MSTK_REG_MONTH(regs);
- rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
- rtc_tm->tm_wday = MSTK_REG_DOW(regs);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
-
- rtc_tm->tm_mon--;
- rtc_tm->tm_wday--;
- rtc_tm->tm_year -= 1900;
-}
-
-static int mostek_set_rtc_time(struct rtc_time *rtc_tm)
-{
- unsigned char mon, day, hrs, min, sec, wday;
- void __iomem *regs = mstk48t02_regs;
- unsigned int yrs;
- u8 tmp;
-
- yrs = rtc_tm->tm_year + 1900;
- mon = rtc_tm->tm_mon + 1;
- day = rtc_tm->tm_mday;
- wday = rtc_tm->tm_wday + 1;
- hrs = rtc_tm->tm_hour;
- min = rtc_tm->tm_min;
- sec = rtc_tm->tm_sec;
-
- spin_lock_irq(&mostek_lock);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- MSTK_SET_REG_SEC(regs, sec);
- MSTK_SET_REG_MIN(regs, min);
- MSTK_SET_REG_HOUR(regs, hrs);
- MSTK_SET_REG_DOW(regs, wday);
- MSTK_SET_REG_DOM(regs, day);
- MSTK_SET_REG_MONTH(regs, mon);
- MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
-
- return 0;
-}
-
-struct mini_rtc_ops {
- void (*get_rtc_time)(struct rtc_time *);
- int (*set_rtc_time)(struct rtc_time *);
-};
-
-static struct mini_rtc_ops starfire_rtc_ops = {
- .get_rtc_time = starfire_get_rtc_time,
- .set_rtc_time = starfire_set_rtc_time,
-};
-
-static struct mini_rtc_ops hypervisor_rtc_ops = {
- .get_rtc_time = hypervisor_get_rtc_time,
- .set_rtc_time = hypervisor_set_rtc_time,
-};
-
-#ifdef CONFIG_PCI
-static struct mini_rtc_ops bq4802_rtc_ops = {
- .get_rtc_time = bq4802_get_rtc_time,
- .set_rtc_time = bq4802_set_rtc_time,
-};
-
-static struct mini_rtc_ops cmos_rtc_ops = {
- .get_rtc_time = cmos_get_rtc_time,
- .set_rtc_time = cmos_set_rtc_time,
-};
-#endif /* CONFIG_PCI */
-
-static struct mini_rtc_ops mostek_rtc_ops = {
- .get_rtc_time = mostek_get_rtc_time,
- .set_rtc_time = mostek_set_rtc_time,
-};
-
-static struct mini_rtc_ops *mini_rtc_ops;
-
-static inline void mini_get_rtc_time(struct rtc_time *time)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&rtc_lock, flags);
- mini_rtc_ops->get_rtc_time(time);
- spin_unlock_irqrestore(&rtc_lock, flags);
-}
-
-static inline int mini_set_rtc_time(struct rtc_time *time)
-{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&rtc_lock, flags);
- err = mini_rtc_ops->set_rtc_time(time);
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return err;
-}
-
-static int mini_rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct rtc_time wtime;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
-
- case RTC_PLL_GET:
- return -EINVAL;
-
- case RTC_PLL_SET:
- return -EINVAL;
-
- case RTC_UIE_OFF: /* disable ints from RTC updates. */
- return 0;
-
- case RTC_UIE_ON: /* enable ints for RTC updates. */
- return -EINVAL;
-
- case RTC_RD_TIME: /* Read the time/date from RTC */
- /* this doesn't get week-day, who cares */
- memset(&wtime, 0, sizeof(wtime));
- mini_get_rtc_time(&wtime);
-
- return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
-
- case RTC_SET_TIME: /* Set the RTC */
- {
- int year, days;
-
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
- if (copy_from_user(&wtime, argp, sizeof(wtime)))
- return -EFAULT;
-
- year = wtime.tm_year + 1900;
- days = month_days[wtime.tm_mon] +
- ((wtime.tm_mon == 1) && leapyear(year));
-
- if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) ||
- (wtime.tm_mday < 1))
- return -EINVAL;
-
- if (wtime.tm_mday < 0 || wtime.tm_mday > days)
- return -EINVAL;
-
- if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
- wtime.tm_min < 0 || wtime.tm_min >= 60 ||
- wtime.tm_sec < 0 || wtime.tm_sec >= 60)
- return -EINVAL;
-
- return mini_set_rtc_time(&wtime);
- }
- }
-
- return -EINVAL;
-}
-
-static int mini_rtc_open(struct inode *inode, struct file *file)
-{
- lock_kernel();
- if (mini_rtc_status & RTC_IS_OPEN) {
- unlock_kernel();
- return -EBUSY;
- }
-
- mini_rtc_status |= RTC_IS_OPEN;
- unlock_kernel();
-
- return 0;
-}
-
-static int mini_rtc_release(struct inode *inode, struct file *file)
-{
- mini_rtc_status &= ~RTC_IS_OPEN;
- return 0;
-}
-
-
-static const struct file_operations mini_rtc_fops = {
- .owner = THIS_MODULE,
- .ioctl = mini_rtc_ioctl,
- .open = mini_rtc_open,
- .release = mini_rtc_release,
-};
-
-static struct miscdevice rtc_mini_dev =
-{
- .minor = RTC_MINOR,
- .name = "rtc",
- .fops = &mini_rtc_fops,
-};
-
-static int __init rtc_mini_init(void)
-{
- int retval;
-
- if (tlb_type == hypervisor)
- mini_rtc_ops = &hypervisor_rtc_ops;
- else if (this_is_starfire)
- mini_rtc_ops = &starfire_rtc_ops;
-#ifdef CONFIG_PCI
- else if (bq4802_regs)
- mini_rtc_ops = &bq4802_rtc_ops;
- else if (ds1287_regs)
- mini_rtc_ops = &cmos_rtc_ops;
-#endif /* CONFIG_PCI */
- else if (mstk48t02_regs)
- mini_rtc_ops = &mostek_rtc_ops;
- else
- return -ENODEV;
-
- printk(KERN_INFO "Mini RTC Driver\n");
-
- retval = misc_register(&rtc_mini_dev);
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static void __exit rtc_mini_exit(void)
-{
- misc_deregister(&rtc_mini_dev);
-}
-
int __devinit read_current_timer(unsigned long *timer_val)
{
*timer_val = tick_ops->get_tick();
return 0;
}
-
-module_init(rtc_mini_init);
-module_exit(rtc_mini_exit);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index c824df13f58..81ccd22e78d 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -38,6 +38,7 @@
#include <asm/timer.h>
#include <asm/head.h>
#include <asm/prom.h>
+#include <asm/memctrl.h>
#include "entry.h"
#include "kstack.h"
@@ -129,6 +130,56 @@ void do_BUG(const char *file, int line)
}
#endif
+static DEFINE_SPINLOCK(dimm_handler_lock);
+static dimm_printer_t dimm_handler;
+
+static int sprintf_dimm(int synd_code, unsigned long paddr, char *buf, int buflen)
+{
+ unsigned long flags;
+ int ret = -ENODEV;
+
+ spin_lock_irqsave(&dimm_handler_lock, flags);
+ if (dimm_handler) {
+ ret = dimm_handler(synd_code, paddr, buf, buflen);
+ } else if (tlb_type == spitfire) {
+ if (prom_getunumber(synd_code, paddr, buf, buflen) == -1)
+ ret = -EINVAL;
+ else
+ ret = 0;
+ } else
+ ret = -ENODEV;
+ spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+ return ret;
+}
+
+int register_dimm_printer(dimm_printer_t func)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dimm_handler_lock, flags);
+ if (!dimm_handler)
+ dimm_handler = func;
+ else
+ ret = -EEXIST;
+ spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_dimm_printer);
+
+void unregister_dimm_printer(dimm_printer_t func)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dimm_handler_lock, flags);
+ if (dimm_handler == func)
+ dimm_handler = NULL;
+ spin_unlock_irqrestore(&dimm_handler_lock, flags);
+}
+EXPORT_SYMBOL_GPL(unregister_dimm_printer);
+
void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
siginfo_t info;
@@ -291,10 +342,7 @@ void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
}
#ifdef CONFIG_PCI
-/* This is really pathetic... */
-extern volatile int pci_poke_in_progress;
-extern volatile int pci_poke_cpu;
-extern volatile int pci_poke_faulted;
+#include "pci_impl.h"
#endif
/* When access exceptions happen, we must do this. */
@@ -376,8 +424,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un
if (udbl & bit) {
scode = ecc_syndrome_table[udbl & 0xff];
- if (prom_getunumber(scode, afar,
- memmod_str, sizeof(memmod_str)) == -1)
+ if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
p = syndrome_unknown;
else
p = memmod_str;
@@ -388,8 +435,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un
if (udbh & bit) {
scode = ecc_syndrome_table[udbh & 0xff];
- if (prom_getunumber(scode, afar,
- memmod_str, sizeof(memmod_str)) == -1)
+ if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
p = syndrome_unknown;
else
p = memmod_str;
@@ -1062,8 +1108,6 @@ static const char *cheetah_get_string(unsigned long bit)
return "???";
}
-extern int chmc_getunumber(int, unsigned long, char *, int);
-
static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info,
unsigned long afsr, unsigned long afar, int recoverable)
{
@@ -1105,7 +1149,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in
syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
syndrome = cheetah_ecc_syntab[syndrome];
- ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+ ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
if (ret != -1)
printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
(recoverable ? KERN_WARNING : KERN_CRIT),
@@ -1116,7 +1160,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in
syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
syndrome = cheetah_mtag_syntab[syndrome];
- ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+ ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
if (ret != -1)
printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
(recoverable ? KERN_WARNING : KERN_CRIT),
@@ -2224,7 +2268,6 @@ void die_if_kernel(char *str, struct pt_regs *regs)
extern int handle_popc(u32 insn, struct pt_regs *regs);
extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
-extern int vis_emul(struct pt_regs *, unsigned int);
void do_illegal_instruction(struct pt_regs *regs)
{
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index a490077891a..92b1f8ec01d 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -152,7 +152,7 @@ show_pciobppath_attr(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
show_pciobppath_attr, NULL);
-struct device_node *cdev_node;
+static struct device_node *cdev_node;
static struct vio_dev *root_vdev;
static u64 cdev_cfg_handle;
@@ -371,9 +371,9 @@ static struct mdesc_notifier_client vio_ds_notifier = {
.node_name = "domain-services-port",
};
-const char *channel_devices_node = "channel-devices";
-const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
-const char *cfg_handle_prop = "cfg-handle";
+static const char *channel_devices_node = "channel-devices";
+static const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
+static const char *cfg_handle_prop = "cfg-handle";
static int __init vio_init(void)
{
diff --git a/arch/sparc64/kernel/visemul.c b/arch/sparc64/kernel/visemul.c
index c3fd64706b5..9e05cb5cb85 100644
--- a/arch/sparc64/kernel/visemul.c
+++ b/arch/sparc64/kernel/visemul.c
@@ -243,7 +243,7 @@ static inline unsigned int *fps_regaddr(struct fpustate *f,
struct edge_tab {
u16 left, right;
};
-struct edge_tab edge8_tab[8] = {
+static struct edge_tab edge8_tab[8] = {
{ 0xff, 0x80 },
{ 0x7f, 0xc0 },
{ 0x3f, 0xe0 },
@@ -253,7 +253,7 @@ struct edge_tab edge8_tab[8] = {
{ 0x03, 0xfe },
{ 0x01, 0xff },
};
-struct edge_tab edge8_tab_l[8] = {
+static struct edge_tab edge8_tab_l[8] = {
{ 0xff, 0x01 },
{ 0xfe, 0x03 },
{ 0xfc, 0x07 },
@@ -263,23 +263,23 @@ struct edge_tab edge8_tab_l[8] = {
{ 0xc0, 0x7f },
{ 0x80, 0xff },
};
-struct edge_tab edge16_tab[4] = {
+static struct edge_tab edge16_tab[4] = {
{ 0xf, 0x8 },
{ 0x7, 0xc },
{ 0x3, 0xe },
{ 0x1, 0xf },
};
-struct edge_tab edge16_tab_l[4] = {
+static struct edge_tab edge16_tab_l[4] = {
{ 0xf, 0x1 },
{ 0xe, 0x3 },
{ 0xc, 0x7 },
{ 0x8, 0xf },
};
-struct edge_tab edge32_tab[2] = {
+static struct edge_tab edge32_tab[2] = {
{ 0x3, 0x2 },
{ 0x1, 0x3 },
};
-struct edge_tab edge32_tab_l[2] = {
+static struct edge_tab edge32_tab_l[2] = {
{ 0x3, 0x1 },
{ 0x2, 0x3 },
};
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index ea7d7ae76bc..a9e474bf638 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -51,43 +51,6 @@ static inline int notify_page_fault(struct pt_regs *regs)
}
#endif
-/*
- * To debug kernel to catch accesses to certain virtual/physical addresses.
- * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
- * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses.
- * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be
- * watched. This is only useful on a single cpu machine for now. After the watchpoint
- * is detected, the process causing it will be killed, thus preventing an infinite loop.
- */
-void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode)
-{
- unsigned long lsubits;
-
- __asm__ __volatile__("ldxa [%%g0] %1, %0"
- : "=r" (lsubits)
- : "i" (ASI_LSU_CONTROL));
- lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM |
- LSU_CONTROL_PR | LSU_CONTROL_VR |
- LSU_CONTROL_PW | LSU_CONTROL_VW);
-
- __asm__ __volatile__("stxa %0, [%1] %2\n\t"
- "membar #Sync"
- : /* no outputs */
- : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT),
- "i" (ASI_DMMU));
-
- lsubits |= ((unsigned long)mask << (mode ? 25 : 33));
- if (flags & VM_READ)
- lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR);
- if (flags & VM_WRITE)
- lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW);
- __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
- "membar #Sync"
- : /* no outputs */
- : "r" (lsubits), "i" (ASI_LSU_CONTROL)
- : "memory");
-}
-
static void __kprobes unhandled_fault(unsigned long address,
struct task_struct *tsk,
struct pt_regs *regs)
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index a41df7bef03..3c10daf8fc0 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -46,15 +46,11 @@
#include <asm/tsb.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
-#include <asm/sstate.h>
#include <asm/mdesc.h>
#include <asm/cpudata.h>
#include <asm/irq.h>
-#define MAX_PHYS_ADDRESS (1UL << 42UL)
-#define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL)
-#define KPTE_BITMAP_BYTES \
- ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+#include "init.h"
unsigned long kern_linear_pte_xor[2] __read_mostly;
@@ -416,17 +412,9 @@ void mmu_info(struct seq_file *m)
#endif /* CONFIG_DEBUG_DCFLUSH */
}
-struct linux_prom_translation {
- unsigned long virt;
- unsigned long size;
- unsigned long data;
-};
-
-/* Exported for kernel TLB miss handling in ktlb.S */
struct linux_prom_translation prom_trans[512] __read_mostly;
unsigned int prom_trans_ents __read_mostly;
-/* Exported for SMP bootup purposes. */
unsigned long kern_locked_tte_data;
/* The obp translations are saved based on 8k pagesize, since obp can
@@ -938,6 +926,10 @@ int of_node_to_nid(struct device_node *dp)
int count, nid;
u64 grp;
+ /* This is the right thing to do on currently supported
+ * SUN4U NUMA platforms as well, as the PCI controller does
+ * not sit behind any particular memory controller.
+ */
if (!mlgroups)
return -1;
@@ -1206,8 +1198,44 @@ out:
return err;
}
+static int __init numa_parse_jbus(void)
+{
+ unsigned long cpu, index;
+
+ /* NUMA node id is encoded in bits 36 and higher, and there is
+ * a 1-to-1 mapping from CPU ID to NUMA node ID.
+ */
+ index = 0;
+ for_each_present_cpu(cpu) {
+ numa_cpu_lookup_table[cpu] = index;
+ numa_cpumask_lookup_table[index] = cpumask_of_cpu(cpu);
+ node_masks[index].mask = ~((1UL << 36UL) - 1UL);
+ node_masks[index].val = cpu << 36UL;
+
+ index++;
+ }
+ num_node_masks = index;
+
+ add_node_ranges();
+
+ for (index = 0; index < num_node_masks; index++) {
+ allocate_node_data(index);
+ node_set_online(index);
+ }
+
+ return 0;
+}
+
static int __init numa_parse_sun4u(void)
{
+ if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+ unsigned long ver;
+
+ __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID)
+ return numa_parse_jbus();
+ }
return -1;
}
@@ -1633,8 +1661,6 @@ void __cpuinit sun4v_ktsb_register(void)
/* paging_init() sets up the page tables */
-extern void central_probe(void);
-
static unsigned long last_valid_pfn;
pgd_t swapper_pg_dir[2048];
@@ -1679,8 +1705,6 @@ void __init paging_init(void)
kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
- sstate_booting();
-
/* Invalidate both kernel TSBs. */
memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
#ifndef CONFIG_DEBUG_PAGEALLOC
@@ -1803,9 +1827,6 @@ void __init paging_init(void)
}
printk("Booting Linux...\n");
-
- central_probe();
- cpu_probe();
}
int __init page_in_phys_avail(unsigned long paddr)
@@ -2032,7 +2053,6 @@ pgprot_t PAGE_COPY __read_mostly;
pgprot_t PAGE_SHARED __read_mostly;
EXPORT_SYMBOL(PAGE_SHARED);
-pgprot_t PAGE_EXEC __read_mostly;
unsigned long pg_iobits __read_mostly;
unsigned long _PAGE_IE __read_mostly;
@@ -2045,14 +2065,6 @@ unsigned long _PAGE_CACHE __read_mostly;
EXPORT_SYMBOL(_PAGE_CACHE);
#ifdef CONFIG_SPARSEMEM_VMEMMAP
-
-#define VMEMMAP_CHUNK_SHIFT 22
-#define VMEMMAP_CHUNK (1UL << VMEMMAP_CHUNK_SHIFT)
-#define VMEMMAP_CHUNK_MASK ~(VMEMMAP_CHUNK - 1UL)
-#define VMEMMAP_ALIGN(x) (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
-
-#define VMEMMAP_SIZE ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
- sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
unsigned long vmemmap_table[VMEMMAP_SIZE];
int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
@@ -2136,7 +2148,6 @@ static void __init sun4u_pgprot_init(void)
_PAGE_CACHE_4U | _PAGE_P_4U |
__ACCESS_BITS_4U | __DIRTY_BITS_4U |
_PAGE_EXEC_4U | _PAGE_L_4U);
- PAGE_EXEC = __pgprot(_PAGE_EXEC_4U);
_PAGE_IE = _PAGE_IE_4U;
_PAGE_E = _PAGE_E_4U;
@@ -2147,10 +2158,10 @@ static void __init sun4u_pgprot_init(void)
#ifdef CONFIG_DEBUG_PAGEALLOC
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#else
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#endif
kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |
_PAGE_P_4U | _PAGE_W_4U);
@@ -2188,7 +2199,6 @@ static void __init sun4v_pgprot_init(void)
__ACCESS_BITS_4V | __DIRTY_BITS_4V |
_PAGE_EXEC_4V);
PAGE_KERNEL_LOCKED = PAGE_KERNEL;
- PAGE_EXEC = __pgprot(_PAGE_EXEC_4V);
_PAGE_IE = _PAGE_IE_4V;
_PAGE_E = _PAGE_E_4V;
@@ -2196,20 +2206,20 @@ static void __init sun4v_pgprot_init(void)
#ifdef CONFIG_DEBUG_PAGEALLOC
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#else
kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#endif
kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |
_PAGE_P_4V | _PAGE_W_4V);
#ifdef CONFIG_DEBUG_PAGEALLOC
kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#else
kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
- 0xfffff80000000000;
+ 0xfffff80000000000UL;
#endif
kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
_PAGE_P_4V | _PAGE_W_4V);
diff --git a/arch/sparc64/mm/init.h b/arch/sparc64/mm/init.h
new file mode 100644
index 00000000000..16063870a48
--- /dev/null
+++ b/arch/sparc64/mm/init.h
@@ -0,0 +1,49 @@
+#ifndef _SPARC64_MM_INIT_H
+#define _SPARC64_MM_INIT_H
+
+/* Most of the symbols in this file are defined in init.c and
+ * marked non-static so that assembler code can get at them.
+ */
+
+#define MAX_PHYS_ADDRESS (1UL << 42UL)
+#define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL)
+#define KPTE_BITMAP_BYTES \
+ ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+
+extern unsigned long kern_linear_pte_xor[2];
+extern unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+extern unsigned int sparc64_highest_unlocked_tlb_ent;
+extern unsigned long sparc64_kern_pri_context;
+extern unsigned long sparc64_kern_pri_nuc_bits;
+extern unsigned long sparc64_kern_sec_context;
+extern void mmu_info(struct seq_file *m);
+
+struct linux_prom_translation {
+ unsigned long virt;
+ unsigned long size;
+ unsigned long data;
+};
+
+/* Exported for kernel TLB miss handling in ktlb.S */
+extern struct linux_prom_translation prom_trans[512];
+extern unsigned int prom_trans_ents;
+
+/* Exported for SMP bootup purposes. */
+extern unsigned long kern_locked_tte_data;
+
+extern void prom_world(int enter);
+
+extern void free_initmem(void);
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+#define VMEMMAP_CHUNK_SHIFT 22
+#define VMEMMAP_CHUNK (1UL << VMEMMAP_CHUNK_SHIFT)
+#define VMEMMAP_CHUNK_MASK ~(VMEMMAP_CHUNK - 1UL)
+#define VMEMMAP_ALIGN(x) (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
+
+#define VMEMMAP_SIZE ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
+ sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
+extern unsigned long vmemmap_table[VMEMMAP_SIZE];
+#endif
+
+#endif /* _SPARC64_MM_INIT_H */
diff --git a/arch/sparc64/mm/tlb.c b/arch/sparc64/mm/tlb.c
index ae24919cba7..d8f21e24a82 100644
--- a/arch/sparc64/mm/tlb.c
+++ b/arch/sparc64/mm/tlb.c
@@ -19,7 +19,7 @@
/* Heavily inspired by the ppc64 code. */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers) = { 0, };
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
void flush_tlb_pending(void)
{
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index e09edfa560d..1f57c113df6 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -9,8 +9,9 @@ config UML_X86
default y
config X86_32
- bool
- default y
+ bool
+ default y
+ select HAVE_AOUT
config RWSEM_XCHGADD_ALGORITHM
def_bool y
@@ -42,6 +43,3 @@ config ARCH_REUSE_HOST_VSYSCALL_AREA
config GENERIC_HWEIGHT
bool
default y
-
-config ARCH_SUPPORTS_AOUT
- def_bool y
diff --git a/arch/um/Kconfig.x86_64 b/arch/um/Kconfig.x86_64
index 5696e7b374b..40b3407cfe1 100644
--- a/arch/um/Kconfig.x86_64
+++ b/arch/um/Kconfig.x86_64
@@ -37,6 +37,3 @@ config SMP_BROKEN
config GENERIC_HWEIGHT
bool
default y
-
-config ARCH_SUPPORTS_AOUT
- def_bool y
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index d741f35d7b3..14a102e877d 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -275,6 +275,8 @@ int line_ioctl(struct tty_struct *tty, struct file * file,
case TIOCGLTC:
case TIOCSLTC:
#endif
+ /* Note: these are out of date as we now have TCGETS2 etc but this
+ whole lot should probably go away */
case TCGETS:
case TCSETSF:
case TCSETSW:
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 44d4f2130d0..f65c2744d57 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -18,6 +18,7 @@ config X86_64
### Arch settings
config X86
def_bool y
+ select HAVE_AOUT if X86_32
select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_IDE
select HAVE_OPROFILE
@@ -152,9 +153,6 @@ config AUDIT_ARCH
bool
default X86_64
-config ARCH_SUPPORTS_AOUT
- def_bool y
-
config ARCH_SUPPORTS_OPTIMIZED_INLINING
def_bool y
@@ -778,23 +776,45 @@ config X86_REBOOTFIXUPS
Say N otherwise.
config MICROCODE
- tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
+ tristate "/dev/cpu/microcode - microcode support"
select FW_LOADER
---help---
If you say Y here, you will be able to update the microcode on
- Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
- Pentium III, Pentium 4, Xeon etc. You will obviously need the
- actual microcode binary data itself which is not shipped with the
- Linux kernel.
+ certain Intel and AMD processors. The Intel support is for the
+ IA32 family, e.g. Pentium Pro, Pentium II, Pentium III,
+ Pentium 4, Xeon etc. The AMD support is for family 0x10 and
+ 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra.
+ You will obviously need the actual microcode binary data itself
+ which is not shipped with the Linux kernel.
- For latest news and information on obtaining all the required
- ingredients for this driver, check:
- <http://www.urbanmyth.org/microcode/>.
+ This option selects the general module only, you need to select
+ at least one vendor specific module as well.
To compile this driver as a module, choose M here: the
module will be called microcode.
-config MICROCODE_OLD_INTERFACE
+config MICROCODE_INTEL
+ bool "Intel microcode patch loading support"
+ depends on MICROCODE
+ default MICROCODE
+ select FW_LOADER
+ --help---
+ This options enables microcode patch loading support for Intel
+ processors.
+
+ For latest news and information on obtaining all the required
+ Intel ingredients for this driver, check:
+ <http://www.urbanmyth.org/microcode/>.
+
+config MICROCODE_AMD
+ bool "AMD microcode patch loading support"
+ depends on MICROCODE
+ select FW_LOADER
+ --help---
+ If you select this option, microcode patch loading support for AMD
+ processors will be enabled.
+
+ config MICROCODE_OLD_INTERFACE
def_bool y
depends on MICROCODE
@@ -1061,6 +1081,56 @@ config HIGHPTE
low memory. Setting this option will put user-space page table
entries in high memory.
+config X86_CHECK_BIOS_CORRUPTION
+ bool "Check for low memory corruption"
+ help
+ Periodically check for memory corruption in low memory, which
+ is suspected to be caused by BIOS. Even when enabled in the
+ configuration, it is disabled at runtime. Enable it by
+ setting "memory_corruption_check=1" on the kernel command
+ line. By default it scans the low 64k of memory every 60
+ seconds; see the memory_corruption_check_size and
+ memory_corruption_check_period parameters in
+ Documentation/kernel-parameters.txt to adjust this.
+
+ When enabled with the default parameters, this option has
+ almost no overhead, as it reserves a relatively small amount
+ of memory and scans it infrequently. It both detects corruption
+ and prevents it from affecting the running system.
+
+ It is, however, intended as a diagnostic tool; if repeatable
+ BIOS-originated corruption always affects the same memory,
+ you can use memmap= to prevent the kernel from using that
+ memory.
+
+config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+ bool "Set the default setting of memory_corruption_check"
+ depends on X86_CHECK_BIOS_CORRUPTION
+ default y
+ help
+ Set whether the default state of memory_corruption_check is
+ on or off.
+
+config X86_RESERVE_LOW_64K
+ bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
+ default y
+ help
+ Reserve the first 64K of physical RAM on BIOSes that are known
+ to potentially corrupt that memory range. A numbers of BIOSes are
+ known to utilize this area during suspend/resume, so it must not
+ be used by the kernel.
+
+ Set this to N if you are absolutely sure that you trust the BIOS
+ to get all its memory reservations and usages right.
+
+ If you have doubts about the BIOS (e.g. suspend/resume does not
+ work or there's kernel crashes after certain hardware hotplug
+ events) and it's not AMI or Phoenix, then you might want to enable
+ X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
+ corruption patterns.
+
+ Say Y if unsure.
+
config MATH_EMULATION
bool
prompt "Math emulation" if X86_32
@@ -1813,7 +1883,7 @@ config IA32_EMULATION
config IA32_AOUT
tristate "IA32 a.out support"
- depends on IA32_EMULATION && ARCH_SUPPORTS_AOUT
+ depends on IA32_EMULATION
help
Support old a.out binaries in the 32bit emulation.
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index f8843c3ae77..0b7c4a3f065 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -38,8 +38,7 @@ config M386
- "Crusoe" for the Transmeta Crusoe series.
- "Efficeon" for the Transmeta Efficeon series.
- "Winchip-C6" for original IDT Winchip.
- - "Winchip-2" for IDT Winchip 2.
- - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+ - "Winchip-2" for IDT Winchips with 3dNow! capabilities.
- "GeodeGX1" for Geode GX1 (Cyrix MediaGX).
- "Geode GX/LX" For AMD Geode GX and LX processors.
- "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
@@ -194,19 +193,11 @@ config MWINCHIPC6
treat this chip as a 586TSC with some extended instructions
and alignment requirements.
-config MWINCHIP2
- bool "Winchip-2"
- depends on X86_32
- help
- Select this for an IDT Winchip-2. Linux and GCC
- treat this chip as a 586TSC with some extended instructions
- and alignment requirements.
-
config MWINCHIP3D
- bool "Winchip-2A/Winchip-3"
+ bool "Winchip-2/Winchip-2A/Winchip-3"
depends on X86_32
help
- Select this for an IDT Winchip-2A or 3. Linux and GCC
+ Select this for an IDT Winchip-2, 2A or 3. Linux and GCC
treat this chip as a 586TSC with some extended instructions
and alignment requirements. Also enable out of order memory
stores for this CPU, which can increase performance of some
@@ -318,7 +309,7 @@ config X86_L1_CACHE_SHIFT
int
default "7" if MPENTIUM4 || X86_GENERIC || GENERIC_CPU || MPSC
default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
- default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+ default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7
config X86_XADD
@@ -360,7 +351,7 @@ config X86_POPAD_OK
config X86_ALIGNMENT_16
def_bool y
- depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
+ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
config X86_INTEL_USERCOPY
def_bool y
@@ -368,7 +359,7 @@ config X86_INTEL_USERCOPY
config X86_USE_PPRO_CHECKSUM
def_bool y
- depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
+ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2
config X86_USE_3DNOW
def_bool y
@@ -376,7 +367,7 @@ config X86_USE_3DNOW
config X86_OOSTORE
def_bool y
- depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
+ depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
#
# P6_NOPs are a relatively minor optimization that require a family >=
@@ -396,7 +387,7 @@ config X86_P6_NOP
config X86_TSC
def_bool y
- depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
+ depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
config X86_CMPXCHG64
def_bool y
@@ -406,7 +397,7 @@ config X86_CMPXCHG64
# generates cmov.
config X86_CMOV
def_bool y
- depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64)
+ depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64)
config X86_MINIMUM_CPU_FAMILY
int
@@ -417,10 +408,9 @@ config X86_MINIMUM_CPU_FAMILY
config X86_DEBUGCTLMSR
def_bool y
- depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
+ depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
menuconfig PROCESSOR_SELECT
- default y
bool "Supported processor vendors" if EMBEDDED
help
This lets you choose what x86 vendor support code your kernel
@@ -430,48 +420,97 @@ config CPU_SUP_INTEL
default y
bool "Support Intel processors" if PROCESSOR_SELECT
help
- This enables extended support for Intel processors
+ This enables detection, tunings and quirks for Intel processors
+
+ You need this enabled if you want your kernel to run on an
+ Intel CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on an Intel
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_CYRIX_32
default y
bool "Support Cyrix processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for Cyrix processors
+ This enables detection, tunings and quirks for Cyrix processors
+
+ You need this enabled if you want your kernel to run on a
+ Cyrix CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Cyrix
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_AMD
default y
bool "Support AMD processors" if PROCESSOR_SELECT
help
- This enables extended support for AMD processors
+ This enables detection, tunings and quirks for AMD processors
+
+ You need this enabled if you want your kernel to run on an
+ AMD CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on an AMD
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_CENTAUR_32
default y
bool "Support Centaur processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for Centaur processors
+ This enables detection, tunings and quirks for Centaur processors
+
+ You need this enabled if you want your kernel to run on a
+ Centaur CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Centaur
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_CENTAUR_64
default y
bool "Support Centaur processors" if PROCESSOR_SELECT
depends on 64BIT
help
- This enables extended support for Centaur processors
+ This enables detection, tunings and quirks for Centaur processors
+
+ You need this enabled if you want your kernel to run on a
+ Centaur CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Centaur
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_TRANSMETA_32
default y
bool "Support Transmeta processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for Transmeta processors
+ This enables detection, tunings and quirks for Transmeta processors
+
+ You need this enabled if you want your kernel to run on a
+ Transmeta CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a Transmeta
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config CPU_SUP_UMC_32
default y
bool "Support UMC processors" if PROCESSOR_SELECT
depends on !64BIT
help
- This enables extended support for UMC processors
+ This enables detection, tunings and quirks for UMC processors
+
+ You need this enabled if you want your kernel to run on a
+ UMC CPU. Disabling this option on other types of CPUs
+ makes the kernel a tiny bit smaller. Disabling it on a UMC
+ CPU might render the kernel unbootable.
+
+ If unsure, say N.
config X86_DS
bool "Debug Store support"
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 092f019e033..2a3dfbd5e67 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -43,6 +43,19 @@ config EARLY_PRINTK
with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash.
+config EARLY_PRINTK_DBGP
+ bool "Early printk via EHCI debug port"
+ default n
+ depends on EARLY_PRINTK && PCI
+ help
+ Write kernel log output directly into the EHCI debug port.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized. For normal operation
+ it is not recommended because it looks ugly and doesn't cooperate
+ with klogd/syslogd or the X server. You should normally N here,
+ unless you want to debug such a crash. You need usb debug device.
+
config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
depends on DEBUG_KERNEL
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
index e372b584e91..80177ec052f 100644
--- a/arch/x86/Makefile_32.cpu
+++ b/arch/x86/Makefile_32.cpu
@@ -28,7 +28,6 @@ cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,-march=athlon)
cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586)
-cflags-$(CONFIG_MWINCHIP2) += $(call cc-option,-march=winchip2,-march=i586)
cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586)
cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686)
@@ -45,3 +44,8 @@ cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx
# cpu entries
cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686))
+# Bug fix for binutils: this option is required in order to keep
+# binutils from generating NOPL instructions against our will.
+ifneq ($(CONFIG_X86_P6_NOP),y)
+cflags-y += $(call cc-option,-Wa$(comma)-mtune=generic32,)
+endif
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 7ee102f9c4f..cd48c721001 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -72,9 +72,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
KBUILD_CFLAGS += $(call cc-option,-m32)
KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
-$(obj)/zImage: IMAGE_OFFSET := 0x1000
$(obj)/zImage: asflags-y := $(SVGA_MODE) $(RAMDISK)
-$(obj)/bzImage: IMAGE_OFFSET := 0x100000
$(obj)/bzImage: ccflags-y := -D__BIG_KERNEL__
$(obj)/bzImage: asflags-y := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
$(obj)/bzImage: BUILDFLAGS := -b
@@ -117,7 +115,7 @@ $(obj)/setup.bin: $(obj)/setup.elf FORCE
$(call if_changed,objcopy)
$(obj)/compressed/vmlinux: FORCE
- $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
+ $(Q)$(MAKE) $(build)=$(obj)/compressed $@
# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
FDARGS =
@@ -181,6 +179,7 @@ isoimage: $(BOOTIMAGE)
mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
$(obj)/isoimage
+ isohybrid $(obj)/image.iso 2>/dev/null || true
rm -rf $(obj)/isoimage
zlilo: $(BOOTIMAGE)
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 92fdd35bd93..1771c804e02 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -27,9 +27,8 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
-ifeq ($(CONFIG_X86_32),y)
-targets += vmlinux.bin.all vmlinux.relocs
-hostprogs-y := relocs
+targets += vmlinux.bin.all vmlinux.relocs relocs
+hostprogs-$(CONFIG_X86_32) += relocs
quiet_cmd_relocs = RELOCS $@
cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
@@ -43,6 +42,8 @@ quiet_cmd_relocbin = BUILD $@
$(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
$(call if_changed,relocbin)
+ifeq ($(CONFIG_X86_32),y)
+
ifdef CONFIG_RELOCATABLE
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
$(call if_changed,gzip)
@@ -59,6 +60,5 @@ $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
endif
-
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
$(call if_changed,ld)
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c
index d93cbc6464d..1aae8f3e5ca 100644
--- a/arch/x86/boot/edd.c
+++ b/arch/x86/boot/edd.c
@@ -41,6 +41,7 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
char *mbrbuf_ptr, *mbrbuf_end;
u32 buf_base, mbr_base;
extern char _end[];
+ u16 mbr_magic;
sector_size = ei->params.bytes_per_sector;
if (!sector_size)
@@ -58,11 +59,15 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
return -1;
+ memset(mbrbuf_ptr, 0, sector_size);
if (read_mbr(devno, mbrbuf_ptr))
return -1;
*mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
- return 0;
+ mbr_magic = *(u16 *)&mbrbuf_ptr[510];
+
+ /* check for valid MBR magic */
+ return mbr_magic == 0xAA55 ? 0 : -1;
}
static int get_edd_info(u8 devno, struct edd_info *ei)
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 401ad998ad0..1e6fe0214c8 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -224,7 +224,7 @@ static void vesa_store_pm_info(void)
static void vesa_store_mode_params_graphics(void)
{
/* Tell the kernel we're in VESA graphics mode */
- boot_params.screen_info.orig_video_isVGA = 0x23;
+ boot_params.screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
/* Mode parameters */
boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index ef9a52005ec..52d0359719d 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -213,7 +213,6 @@ CONFIG_M686=y
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MGEODE_LX is not set
@@ -1535,7 +1534,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_VGA_CONSOLE=y
CONFIG_VGACON_SOFT_SCROLLBACK=y
CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
CONFIG_LOGO=y
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index e620ea6e2a7..f0a03d7a7d6 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -210,7 +210,6 @@ CONFIG_X86_PC=y
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MGEODE_LX is not set
@@ -1505,7 +1504,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_VGA_CONSOLE=y
CONFIG_VGACON_SOFT_SCROLLBACK=y
CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
CONFIG_LOGO=y
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 8d64c1bc847..4bc02b23674 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
savesegment(es, tmp);
err |= __put_user(tmp, (unsigned int __user *)&sc->es);
- err |= __put_user((u32)regs->di, &sc->di);
- err |= __put_user((u32)regs->si, &sc->si);
- err |= __put_user((u32)regs->bp, &sc->bp);
- err |= __put_user((u32)regs->sp, &sc->sp);
- err |= __put_user((u32)regs->bx, &sc->bx);
- err |= __put_user((u32)regs->dx, &sc->dx);
- err |= __put_user((u32)regs->cx, &sc->cx);
- err |= __put_user((u32)regs->ax, &sc->ax);
- err |= __put_user((u32)regs->cs, &sc->cs);
- err |= __put_user((u32)regs->ss, &sc->ss);
+ err |= __put_user(regs->di, &sc->di);
+ err |= __put_user(regs->si, &sc->si);
+ err |= __put_user(regs->bp, &sc->bp);
+ err |= __put_user(regs->sp, &sc->sp);
+ err |= __put_user(regs->bx, &sc->bx);
+ err |= __put_user(regs->dx, &sc->dx);
+ err |= __put_user(regs->cx, &sc->cx);
+ err |= __put_user(regs->ax, &sc->ax);
+ err |= __put_user(regs->cs, &sc->cs);
+ err |= __put_user(regs->ss, &sc->ss);
err |= __put_user(current->thread.trap_no, &sc->trapno);
err |= __put_user(current->thread.error_code, &sc->err);
- err |= __put_user((u32)regs->ip, &sc->ip);
- err |= __put_user((u32)regs->flags, &sc->flags);
- err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
+ err |= __put_user(regs->ip, &sc->ip);
+ err |= __put_user(regs->flags, &sc->flags);
+ err |= __put_user(regs->sp, &sc->sp_at_signal);
tmp = save_i387_xstate_ia32(fpstate);
if (tmp < 0)
err = -EFAULT;
- else {
- clear_used_math();
- stts();
+ else
err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
&sc->fpstate);
- }
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
@@ -444,21 +441,18 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
- err |= __put_user(sig, &frame->sig);
- if (err)
- goto give_sigsegv;
+ if (__put_user(sig, &frame->sig))
+ return -EFAULT;
- err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
- if (err)
- goto give_sigsegv;
+ if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+ return -EFAULT;
if (_COMPAT_NSIG_WORDS > 1) {
- err |= __copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- if (err)
- goto give_sigsegv;
+ if (__copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask)))
+ return -EFAULT;
}
if (ka->sa.sa_flags & SA_RESTORER) {
@@ -479,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
*/
err |= __copy_to_user(frame->retcode, &code, 8);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
@@ -502,10 +496,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
#endif
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -533,14 +523,14 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
err |= __put_user(sig, &frame->sig);
err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
err |= copy_siginfo_to_user32(&frame->info, info);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Create the ucontext. */
if (cpu_has_xsave)
@@ -556,7 +546,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
@@ -571,7 +561,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
*/
err |= __copy_to_user(frame->retcode, &code, 8);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
@@ -599,8 +589,4 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#endif
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index ffc1bb4fed7..eb4314768bf 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -39,11 +39,11 @@
.endm
/* clobbers %eax */
- .macro CLEAR_RREGS
+ .macro CLEAR_RREGS _r9=rax
xorl %eax,%eax
movq %rax,R11(%rsp)
movq %rax,R10(%rsp)
- movq %rax,R9(%rsp)
+ movq %\_r9,R9(%rsp)
movq %rax,R8(%rsp)
.endm
@@ -52,11 +52,10 @@
* We don't reload %eax because syscall_trace_enter() returned
* the value it wants us to use in the table lookup.
*/
- .macro LOAD_ARGS32 offset
- movl \offset(%rsp),%r11d
- movl \offset+8(%rsp),%r10d
+ .macro LOAD_ARGS32 offset, _r9=0
+ .if \_r9
movl \offset+16(%rsp),%r9d
- movl \offset+24(%rsp),%r8d
+ .endif
movl \offset+40(%rsp),%ecx
movl \offset+48(%rsp),%edx
movl \offset+56(%rsp),%esi
@@ -145,7 +144,7 @@ ENTRY(ia32_sysenter_target)
SAVE_ARGS 0,0,1
/* no need to do an access_ok check here because rbp has been
32bit zero extended */
-1: movl (%rbp),%r9d
+1: movl (%rbp),%ebp
.section __ex_table,"a"
.quad 1b,ia32_badarg
.previous
@@ -157,7 +156,7 @@ ENTRY(ia32_sysenter_target)
cmpl $(IA32_NR_syscalls-1),%eax
ja ia32_badsys
sysenter_do_call:
- IA32_ARG_FIXUP 1
+ IA32_ARG_FIXUP
sysenter_dispatch:
call *ia32_sys_call_table(,%rax,8)
movq %rax,RAX-ARGOFFSET(%rsp)
@@ -234,20 +233,17 @@ sysexit_audit:
#endif
sysenter_tracesys:
- xchgl %r9d,%ebp
#ifdef CONFIG_AUDITSYSCALL
testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
jz sysenter_auditsys
#endif
SAVE_REST
CLEAR_RREGS
- movq %r9,R9(%rsp)
movq $-ENOSYS,RAX(%rsp)/* ptrace can change this for a bad syscall */
movq %rsp,%rdi /* &pt_regs -> arg1 */
call syscall_trace_enter
LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
RESTORE_REST
- xchgl %ebp,%r9d
cmpl $(IA32_NR_syscalls-1),%eax
ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
jmp sysenter_do_call
@@ -314,9 +310,9 @@ ENTRY(ia32_cstar_target)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
CFI_REMEMBER_STATE
jnz cstar_tracesys
-cstar_do_call:
cmpl $IA32_NR_syscalls-1,%eax
ja ia32_badsys
+cstar_do_call:
IA32_ARG_FIXUP 1
cstar_dispatch:
call *ia32_sys_call_table(,%rax,8)
@@ -357,15 +353,13 @@ cstar_tracesys:
#endif
xchgl %r9d,%ebp
SAVE_REST
- CLEAR_RREGS
- movq %r9,R9(%rsp)
+ CLEAR_RREGS r9
movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
movq %rsp,%rdi /* &pt_regs -> arg1 */
call syscall_trace_enter
- LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
+ LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */
RESTORE_REST
xchgl %ebp,%r9d
- movl RSP-ARGOFFSET(%rsp), %r8d
cmpl $(IA32_NR_syscalls-1),%eax
ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
jmp cstar_do_call
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index c9be69fedb7..0d41f0343dc 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -10,7 +10,7 @@ ifdef CONFIG_FTRACE
# Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_tsc.o = -pg
CFLAGS_REMOVE_rtc.o = -pg
-CFLAGS_REMOVE_paravirt.o = -pg
+CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
endif
#
@@ -23,7 +23,7 @@ CFLAGS_hpet.o := $(nostackp)
CFLAGS_tsc.o := $(nostackp)
obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
-obj-y += traps_$(BITS).o irq_$(BITS).o
+obj-y += traps.o irq_$(BITS).o dumpstack_$(BITS).o
obj-y += time_$(BITS).o ioport.o ldt.o
obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o
obj-$(CONFIG_X86_VISWS) += visws_quirks.o
@@ -51,7 +51,6 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
-obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_PCI) += early-quirks.o
apm-y := apm_32.o
obj-$(CONFIG_APM) += apm.o
@@ -90,7 +89,7 @@ obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o
obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o
obj-$(CONFIG_KVM_GUEST) += kvm.o
obj-$(CONFIG_KVM_CLOCK) += kvmclock.o
-obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o
+obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o paravirt-spinlocks.o
obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o
obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o
@@ -100,6 +99,11 @@ scx200-y += scx200_32.o
obj-$(CONFIG_OLPC) += olpc.o
+microcode-y := microcode_core.o
+microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
+microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o
+obj-$(CONFIG_MICROCODE) += microcode.o
+
###
# 64 bit specific files
ifeq ($(CONFIG_X86_64),y)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index c2ac1b4515a..eb875cdc736 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1418,8 +1418,16 @@ static int __init force_acpi_ht(const struct dmi_system_id *d)
*/
static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
{
- pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
- acpi_skip_timer_override = 1;
+ /*
+ * The ati_ixp4x0_rev() early PCI quirk should have set
+ * the acpi_skip_timer_override flag already:
+ */
+ if (!acpi_skip_timer_override) {
+ WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n");
+ pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n",
+ d->ident);
+ acpi_skip_timer_override = 1;
+ }
return 0;
}
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index fb04e49776b..a84ac7b570e 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -444,7 +444,7 @@ void __init alternative_instructions(void)
_text, _etext);
/* Only switch to UP mode if we don't immediately boot others */
- if (num_possible_cpus() == 1 || setup_max_cpus <= 1)
+ if (num_present_cpus() == 1 || setup_max_cpus <= 1)
alternatives_smp_switch(0);
}
#endif
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 148fcfe22f1..4cd8083c58b 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -723,9 +723,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
init_iommu_from_acpi(iommu, h);
init_iommu_devices(iommu);
- pci_enable_device(iommu->dev);
-
- return 0;
+ return pci_enable_device(iommu->dev);
}
/*
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index a91c57cb666..21c831d96af 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -295,6 +295,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
*
* Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
* MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
*/
#define APIC_EILVT_LVTOFF_MCE 0
@@ -319,6 +322,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
return APIC_EILVT_LVTOFF_IBS;
}
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
/*
* Program the next event, relative to now
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 53898b65a6a..94ddb69ae15 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -307,6 +307,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
*
* Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
* MCE interrupts are supported. Thus MCE offset must be set to 0.
+ *
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
*/
#define APIC_EILVT_LVTOFF_MCE 0
@@ -331,6 +334,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
return APIC_EILVT_LVTOFF_IBS;
}
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
/*
* Program the next event, relative to now
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 7581b62df18..25581dcb280 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -124,18 +124,25 @@ static inline int flag_is_changeable_p(u32 flag)
{
u32 f1, f2;
- asm("pushfl\n\t"
- "pushfl\n\t"
- "popl %0\n\t"
- "movl %0,%1\n\t"
- "xorl %2,%0\n\t"
- "pushl %0\n\t"
- "popfl\n\t"
- "pushfl\n\t"
- "popl %0\n\t"
- "popfl\n\t"
- : "=&r" (f1), "=&r" (f2)
- : "ir" (flag));
+ /*
+ * Cyrix and IDT cpus allow disabling of CPUID
+ * so the code below may return different results
+ * when it is executed before and after enabling
+ * the CPUID. Add "volatile" to not allow gcc to
+ * optimize the subsequent calls to this function.
+ */
+ asm volatile ("pushfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "movl %0,%1\n\t"
+ "xorl %2,%0\n\t"
+ "pushl %0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "popfl\n\t"
+ : "=&r" (f1), "=&r" (f2)
+ : "ir" (flag));
return ((f1^f2) & flag) != 0;
}
@@ -719,12 +726,24 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
#endif
}
+#ifdef CONFIG_X86_64
+static void vgetcpu_set_mode(void)
+{
+ if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
+ vgetcpu_mode = VGETCPU_RDTSCP;
+ else
+ vgetcpu_mode = VGETCPU_LSL;
+}
+#endif
+
void __init identify_boot_cpu(void)
{
identify_cpu(&boot_cpu_data);
#ifdef CONFIG_X86_32
sysenter_setup();
enable_sep_cpu();
+#else
+ vgetcpu_set_mode();
#endif
}
@@ -797,7 +816,7 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
else if (c->cpuid_level >= 0)
vendor = c->x86_vendor_id;
- if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
+ if (vendor && !strstr(c->x86_model_id, vendor))
printk(KERN_CONT "%s ", vendor);
if (c->x86_model_id[0])
@@ -1121,16 +1140,5 @@ void __cpuinit cpu_init(void)
xsave_init();
}
-#ifdef CONFIG_HOTPLUG_CPU
-void __cpuinit cpu_uninit(void)
-{
- int cpu = raw_smp_processor_id();
- cpu_clear(cpu, cpu_initialized);
-
- /* lazy TLB state */
- per_cpu(cpu_tlbstate, cpu).state = 0;
- per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
-}
-#endif
#endif
diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c
index a47798b59f0..b4f14c6c09d 100644
--- a/arch/x86/kernel/doublefault_32.c
+++ b/arch/x86/kernel/doublefault_32.c
@@ -66,6 +66,6 @@ struct tss_struct doublefault_tss __cacheline_aligned = {
.ds = __USER_DS,
.fs = __KERNEL_PERCPU,
- .__cr3 = __pa(swapper_pg_dir)
+ .__cr3 = __pa_nodebug(swapper_pg_dir),
}
};
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
new file mode 100644
index 00000000000..201ee359a1a
--- /dev/null
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 8
+#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+ printk(" [<%p>] %s%pS\n", (void *) address,
+ reliable ? "" : "? ", (void *) address);
+}
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+ void *p, unsigned int size, void *end)
+{
+ void *t = tinfo;
+ if (end) {
+ if (p < end && p >= (end-THREAD_SIZE))
+ return 1;
+ else
+ return 0;
+ }
+ return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+ struct stack_frame *next_frame;
+ unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data,
+ unsigned long *end)
+{
+ struct stack_frame *frame = (struct stack_frame *)bp;
+
+ while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+ unsigned long addr;
+
+ addr = *stack;
+ if (__kernel_text_address(addr)) {
+ if ((unsigned long) stack == bp + sizeof(long)) {
+ ops->address(data, addr, 1);
+ frame = frame->next_frame;
+ bp = (unsigned long) frame;
+ } else {
+ ops->address(data, addr, bp == 0);
+ }
+ }
+ stack++;
+ }
+ return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data)
+{
+ if (!task)
+ task = current;
+
+ if (!stack) {
+ unsigned long dummy;
+ stack = &dummy;
+ if (task && task != current)
+ stack = (unsigned long *)task->thread.sp;
+ }
+
+#ifdef CONFIG_FRAME_POINTER
+ if (!bp) {
+ if (task == current) {
+ /* Grab bp right from our regs */
+ get_bp(bp);
+ } else {
+ /* bp is the last reg pushed by switch_to */
+ bp = *(unsigned long *) task->thread.sp;
+ }
+ }
+#endif
+
+ for (;;) {
+ struct thread_info *context;
+
+ context = (struct thread_info *)
+ ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+ bp = print_context_stack(context, stack, bp, ops, data, NULL);
+
+ stack = (unsigned long *)context->previous_esp;
+ if (!stack)
+ break;
+ if (ops->stack(data, "IRQ") < 0)
+ break;
+ touch_nmi_watchdog();
+ }
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+ printk(data);
+ print_symbol(msg, symbol);
+ printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+ printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+ printk("%s <%s> ", (char *)data, name);
+ return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+ touch_nmi_watchdog();
+ printk(data);
+ printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+ .warning = print_trace_warning,
+ .warning_symbol = print_trace_warning_symbol,
+ .stack = print_trace_stack,
+ .address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+ printk("%sCall Trace:\n", log_lvl);
+ dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp)
+{
+ show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+ unsigned long *stack;
+ int i;
+
+ if (sp == NULL) {
+ if (task)
+ sp = (unsigned long *)task->thread.sp;
+ else
+ sp = (unsigned long *)&sp;
+ }
+
+ stack = sp;
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (kstack_end(stack))
+ break;
+ if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+ printk("\n%s", log_lvl);
+ printk(" %08lx", *stack++);
+ touch_nmi_watchdog();
+ }
+ printk("\n");
+ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+ show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+ unsigned long bp = 0;
+ unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+ if (!bp)
+ get_bp(bp);
+#endif
+
+ printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+ current->pid, current->comm, print_tainted(),
+ init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+ show_trace(NULL, NULL, &stack, bp);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+ int i;
+
+ print_modules();
+ __show_regs(regs, 0);
+
+ printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
+ TASK_COMM_LEN, current->comm, task_pid_nr(current),
+ current_thread_info(), current, task_thread_info(current));
+ /*
+ * When in-kernel, we also print out the stack and code at the
+ * time of the fault..
+ */
+ if (!user_mode_vm(regs)) {
+ unsigned int code_prologue = code_bytes * 43 / 64;
+ unsigned int code_len = code_bytes;
+ unsigned char c;
+ u8 *ip;
+
+ printk(KERN_EMERG "Stack:\n");
+ show_stack_log_lvl(NULL, regs, &regs->sp,
+ 0, KERN_EMERG);
+
+ printk(KERN_EMERG "Code: ");
+
+ ip = (u8 *)regs->ip - code_prologue;
+ if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+ /* try starting at IP */
+ ip = (u8 *)regs->ip;
+ code_len = code_len - code_prologue + 1;
+ }
+ for (i = 0; i < code_len; i++, ip++) {
+ if (ip < (u8 *)PAGE_OFFSET ||
+ probe_kernel_address(ip, c)) {
+ printk(" Bad EIP value.");
+ break;
+ }
+ if (ip == (u8 *)regs->ip)
+ printk("<%02x> ", c);
+ else
+ printk("%02x ", c);
+ }
+ }
+ printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+ unsigned short ud2;
+
+ if (ip < PAGE_OFFSET)
+ return 0;
+ if (probe_kernel_address((unsigned short *)ip, ud2))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+ unsigned long flags;
+
+ oops_enter();
+
+ if (die_owner != raw_smp_processor_id()) {
+ console_verbose();
+ raw_local_irq_save(flags);
+ __raw_spin_lock(&die_lock);
+ die_owner = smp_processor_id();
+ die_nest_count = 0;
+ bust_spinlocks(1);
+ } else {
+ raw_local_irq_save(flags);
+ }
+ die_nest_count++;
+ return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+ bust_spinlocks(0);
+ die_owner = -1;
+ add_taint(TAINT_DIE);
+ __raw_spin_unlock(&die_lock);
+ raw_local_irq_restore(flags);
+
+ if (!regs)
+ return;
+
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+ if (panic_on_oops)
+ panic("Fatal exception");
+ oops_exit();
+ do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+ unsigned short ss;
+ unsigned long sp;
+
+ printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+ printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+ printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ printk("DEBUG_PAGEALLOC");
+#endif
+ printk("\n");
+ if (notify_die(DIE_OOPS, str, regs, err,
+ current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+ return 1;
+
+ show_registers(regs);
+ /* Executive summary in case the oops scrolled away */
+ sp = (unsigned long) (&regs->sp);
+ savesegment(ss, ss);
+ if (user_mode(regs)) {
+ sp = regs->sp;
+ ss = regs->ss & 0xffff;
+ }
+ printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+ print_symbol("%s", regs->ip);
+ printk(" SS:ESP %04x:%08lx\n", ss, sp);
+ return 0;
+}
+
+/*
+ * This is gone through when something in the kernel has done something bad
+ * and is about to be terminated:
+ */
+void die(const char *str, struct pt_regs *regs, long err)
+{
+ unsigned long flags = oops_begin();
+
+ if (die_nest_count < 3) {
+ report_bug(regs->ip, regs);
+
+ if (__die(str, regs, err))
+ regs = NULL;
+ } else {
+ printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
+ }
+
+ oops_end(flags, regs, SIGSEGV);
+}
+
+static DEFINE_SPINLOCK(nmi_print_lock);
+
+void notrace __kprobes
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+ if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+ return;
+
+ spin_lock(&nmi_print_lock);
+ /*
+ * We are in trouble anyway, lets at least try
+ * to get a message out:
+ */
+ bust_spinlocks(1);
+ printk(KERN_EMERG "%s", str);
+ printk(" on CPU%d, ip %08lx, registers:\n",
+ smp_processor_id(), regs->ip);
+ show_registers(regs);
+ if (do_panic)
+ panic("Non maskable interrupt");
+ console_silent();
+ spin_unlock(&nmi_print_lock);
+ bust_spinlocks(0);
+
+ /*
+ * If we are in kernel we are probably nested up pretty bad
+ * and might aswell get out now while we still can:
+ */
+ if (!user_mode_vm(regs)) {
+ current->thread.trap_no = 2;
+ crash_kexec(regs);
+ }
+
+ do_exit(SIGSEGV);
+}
+
+static int __init oops_setup(char *s)
+{
+ if (!s)
+ return -EINVAL;
+ if (!strcmp(s, "panic"))
+ panic_on_oops = 1;
+ return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+ if (!s)
+ return -EINVAL;
+ kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+ return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+ code_bytes = simple_strtoul(s, NULL, 0);
+ if (code_bytes > 8192)
+ code_bytes = 8192;
+
+ return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
new file mode 100644
index 00000000000..086cc8118e3
--- /dev/null
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
+ */
+#include <linux/kallsyms.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/hardirq.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/bug.h>
+#include <linux/nmi.h>
+
+#include <asm/stacktrace.h>
+
+#define STACKSLOTS_PER_LINE 4
+#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
+
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
+static unsigned int code_bytes = 64;
+static int die_counter;
+
+void printk_address(unsigned long address, int reliable)
+{
+ printk(" [<%p>] %s%pS\n", (void *) address,
+ reliable ? "" : "? ", (void *) address);
+}
+
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+ unsigned *usedp, char **idp)
+{
+ static char ids[][8] = {
+ [DEBUG_STACK - 1] = "#DB",
+ [NMI_STACK - 1] = "NMI",
+ [DOUBLEFAULT_STACK - 1] = "#DF",
+ [STACKFAULT_STACK - 1] = "#SS",
+ [MCE_STACK - 1] = "#MC",
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+ [N_EXCEPTION_STACKS ...
+ N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
+#endif
+ };
+ unsigned k;
+
+ /*
+ * Iterate over all exception stacks, and figure out whether
+ * 'stack' is in one of them:
+ */
+ for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+ unsigned long end = per_cpu(orig_ist, cpu).ist[k];
+ /*
+ * Is 'stack' above this exception frame's end?
+ * If yes then skip to the next frame.
+ */
+ if (stack >= end)
+ continue;
+ /*
+ * Is 'stack' above this exception frame's start address?
+ * If yes then we found the right frame.
+ */
+ if (stack >= end - EXCEPTION_STKSZ) {
+ /*
+ * Make sure we only iterate through an exception
+ * stack once. If it comes up for the second time
+ * then there's something wrong going on - just
+ * break out and return NULL:
+ */
+ if (*usedp & (1U << k))
+ break;
+ *usedp |= 1U << k;
+ *idp = ids[k];
+ return (unsigned long *)end;
+ }
+ /*
+ * If this is a debug stack, and if it has a larger size than
+ * the usual exception stacks, then 'stack' might still
+ * be within the lower portion of the debug stack:
+ */
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+ if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
+ unsigned j = N_EXCEPTION_STACKS - 1;
+
+ /*
+ * Black magic. A large debug stack is composed of
+ * multiple exception stack entries, which we
+ * iterate through now. Dont look:
+ */
+ do {
+ ++j;
+ end -= EXCEPTION_STKSZ;
+ ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+ } while (stack < end - EXCEPTION_STKSZ);
+ if (*usedp & (1U << j))
+ break;
+ *usedp |= 1U << j;
+ *idp = ids[j];
+ return (unsigned long *)end;
+ }
+#endif
+ }
+ return NULL;
+}
+
+/*
+ * x86-64 can have up to three kernel stacks:
+ * process stack
+ * interrupt stack
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+ void *p, unsigned int size, void *end)
+{
+ void *t = tinfo;
+ if (end) {
+ if (p < end && p >= (end-THREAD_SIZE))
+ return 1;
+ else
+ return 0;
+ }
+ return p > t && p < t + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+ struct stack_frame *next_frame;
+ unsigned long return_address;
+};
+
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data,
+ unsigned long *end)
+{
+ struct stack_frame *frame = (struct stack_frame *)bp;
+
+ while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
+ unsigned long addr;
+
+ addr = *stack;
+ if (__kernel_text_address(addr)) {
+ if ((unsigned long) stack == bp + sizeof(long)) {
+ ops->address(data, addr, 1);
+ frame = frame->next_frame;
+ bp = (unsigned long) frame;
+ } else {
+ ops->address(data, addr, bp == 0);
+ }
+ }
+ stack++;
+ }
+ return bp;
+}
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data)
+{
+ const unsigned cpu = get_cpu();
+ unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
+ unsigned used = 0;
+ struct thread_info *tinfo;
+
+ if (!task)
+ task = current;
+
+ if (!stack) {
+ unsigned long dummy;
+ stack = &dummy;
+ if (task && task != current)
+ stack = (unsigned long *)task->thread.sp;
+ }
+
+#ifdef CONFIG_FRAME_POINTER
+ if (!bp) {
+ if (task == current) {
+ /* Grab bp right from our regs */
+ get_bp(bp);
+ } else {
+ /* bp is the last reg pushed by switch_to */
+ bp = *(unsigned long *) task->thread.sp;
+ }
+ }
+#endif
+
+ /*
+ * Print function call entries in all stacks, starting at the
+ * current stack address. If the stacks consist of nested
+ * exceptions
+ */
+ tinfo = task_thread_info(task);
+ for (;;) {
+ char *id;
+ unsigned long *estack_end;
+ estack_end = in_exception_stack(cpu, (unsigned long)stack,
+ &used, &id);
+
+ if (estack_end) {
+ if (ops->stack(data, id) < 0)
+ break;
+
+ bp = print_context_stack(tinfo, stack, bp, ops,
+ data, estack_end);
+ ops->stack(data, "<EOE>");
+ /*
+ * We link to the next stack via the
+ * second-to-last pointer (index -2 to end) in the
+ * exception stack:
+ */
+ stack = (unsigned long *) estack_end[-2];
+ continue;
+ }
+ if (irqstack_end) {
+ unsigned long *irqstack;
+ irqstack = irqstack_end -
+ (IRQSTACKSIZE - 64) / sizeof(*irqstack);
+
+ if (stack >= irqstack && stack < irqstack_end) {
+ if (ops->stack(data, "IRQ") < 0)
+ break;
+ bp = print_context_stack(tinfo, stack, bp,
+ ops, data, irqstack_end);
+ /*
+ * We link to the next stack (which would be
+ * the process stack normally) the last
+ * pointer (index -1 to end) in the IRQ stack:
+ */
+ stack = (unsigned long *) (irqstack_end[-1]);
+ irqstack_end = NULL;
+ ops->stack(data, "EOI");
+ continue;
+ }
+ }
+ break;
+ }
+
+ /*
+ * This handles the process stack:
+ */
+ bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
+ put_cpu();
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+ printk(data);
+ print_symbol(msg, symbol);
+ printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+ printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+ printk("%s <%s> ", (char *)data, name);
+ return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr, int reliable)
+{
+ touch_nmi_watchdog();
+ printk(data);
+ printk_address(addr, reliable);
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+ .warning = print_trace_warning,
+ .warning_symbol = print_trace_warning_symbol,
+ .stack = print_trace_stack,
+ .address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp, char *log_lvl)
+{
+ printk("%sCall Trace:\n", log_lvl);
+ dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp)
+{
+ show_trace_log_lvl(task, regs, stack, bp, "");
+}
+
+static void
+show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *sp, unsigned long bp, char *log_lvl)
+{
+ unsigned long *stack;
+ int i;
+ const int cpu = smp_processor_id();
+ unsigned long *irqstack_end =
+ (unsigned long *) (cpu_pda(cpu)->irqstackptr);
+ unsigned long *irqstack =
+ (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
+
+ /*
+ * debugging aid: "show_stack(NULL, NULL);" prints the
+ * back trace for this cpu.
+ */
+
+ if (sp == NULL) {
+ if (task)
+ sp = (unsigned long *)task->thread.sp;
+ else
+ sp = (unsigned long *)&sp;
+ }
+
+ stack = sp;
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (stack >= irqstack && stack <= irqstack_end) {
+ if (stack == irqstack_end) {
+ stack = (unsigned long *) (irqstack_end[-1]);
+ printk(" <EOI> ");
+ }
+ } else {
+ if (((long) stack & (THREAD_SIZE-1)) == 0)
+ break;
+ }
+ if (i && ((i % STACKSLOTS_PER_LINE) == 0))
+ printk("\n%s", log_lvl);
+ printk(" %016lx", *stack++);
+ touch_nmi_watchdog();
+ }
+ printk("\n");
+ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+ show_stack_log_lvl(task, NULL, sp, 0, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+ unsigned long bp = 0;
+ unsigned long stack;
+
+#ifdef CONFIG_FRAME_POINTER
+ if (!bp)
+ get_bp(bp);
+#endif
+
+ printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+ current->pid, current->comm, print_tainted(),
+ init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+ show_trace(NULL, NULL, &stack, bp);
+}
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+ int i;
+ unsigned long sp;
+ const int cpu = smp_processor_id();
+ struct task_struct *cur = cpu_pda(cpu)->pcurrent;
+
+ sp = regs->sp;
+ printk("CPU %d ", cpu);
+ __show_regs(regs, 1);
+ printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
+ cur->comm, cur->pid, task_thread_info(cur), cur);
+
+ /*
+ * When in-kernel, we also print out the stack and code at the
+ * time of the fault..
+ */
+ if (!user_mode(regs)) {
+ unsigned int code_prologue = code_bytes * 43 / 64;
+ unsigned int code_len = code_bytes;
+ unsigned char c;
+ u8 *ip;
+
+ printk(KERN_EMERG "Stack:\n");
+ show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
+ regs->bp, KERN_EMERG);
+
+ printk(KERN_EMERG "Code: ");
+
+ ip = (u8 *)regs->ip - code_prologue;
+ if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
+ /* try starting at IP */
+ ip = (u8 *)regs->ip;
+ code_len = code_len - code_prologue + 1;
+ }
+ for (i = 0; i < code_len; i++, ip++) {
+ if (ip < (u8 *)PAGE_OFFSET ||
+ probe_kernel_address(ip, c)) {
+ printk(" Bad RIP value.");
+ break;
+ }
+ if (ip == (u8 *)regs->ip)
+ printk("<%02x> ", c);
+ else
+ printk("%02x ", c);
+ }
+ }
+ printk("\n");
+}
+
+int is_valid_bugaddr(unsigned long ip)
+{
+ unsigned short ud2;
+
+ if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
+
+static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned __kprobes long oops_begin(void)
+{
+ int cpu;
+ unsigned long flags;
+
+ oops_enter();
+
+ /* racy, but better than risking deadlock. */
+ raw_local_irq_save(flags);
+ cpu = smp_processor_id();
+ if (!__raw_spin_trylock(&die_lock)) {
+ if (cpu == die_owner)
+ /* nested oops. should stop eventually */;
+ else
+ __raw_spin_lock(&die_lock);
+ }
+ die_nest_count++;
+ die_owner = cpu;
+ console_verbose();
+ bust_spinlocks(1);
+ return flags;
+}
+
+void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
+{
+ die_owner = -1;
+ bust_spinlocks(0);
+ die_nest_count--;
+ if (!die_nest_count)
+ /* Nest count reaches zero, release the lock. */
+ __raw_spin_unlock(&die_lock);
+ raw_local_irq_restore(flags);
+ if (!regs) {
+ oops_exit();
+ return;
+ }
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+ if (panic_on_oops)
+ panic("Fatal exception");
+ oops_exit();
+ do_exit(signr);
+}
+
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
+{
+ printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+ printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+ printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ printk("DEBUG_PAGEALLOC");
+#endif
+ printk("\n");
+ if (notify_die(DIE_OOPS, str, regs, err,
+ current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+ return 1;
+
+ show_registers(regs);
+ add_taint(TAINT_DIE);
+ /* Executive summary in case the oops scrolled away */
+ printk(KERN_ALERT "RIP ");
+ printk_address(regs->ip, 1);
+ printk(" RSP <%016lx>\n", regs->sp);
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
+ return 0;
+}
+
+void die(const char *str, struct pt_regs *regs, long err)
+{
+ unsigned long flags = oops_begin();
+
+ if (!user_mode(regs))
+ report_bug(regs->ip, regs);
+
+ if (__die(str, regs, err))
+ regs = NULL;
+ oops_end(flags, regs, SIGSEGV);
+}
+
+notrace __kprobes void
+die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+ unsigned long flags;
+
+ if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+ return;
+
+ flags = oops_begin();
+ /*
+ * We are in trouble anyway, lets at least try
+ * to get a message out.
+ */
+ printk(KERN_EMERG "%s", str);
+ printk(" on CPU%d, ip %08lx, registers:\n",
+ smp_processor_id(), regs->ip);
+ show_registers(regs);
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
+ if (do_panic || panic_on_oops)
+ panic("Non maskable interrupt");
+ oops_end(flags, NULL, SIGBUS);
+ nmi_exit();
+ local_irq_enable();
+ do_exit(SIGBUS);
+}
+
+static int __init oops_setup(char *s)
+{
+ if (!s)
+ return -EINVAL;
+ if (!strcmp(s, "panic"))
+ panic_on_oops = 1;
+ return 0;
+}
+early_param("oops", oops_setup);
+
+static int __init kstack_setup(char *s)
+{
+ if (!s)
+ return -EINVAL;
+ kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+ return 0;
+}
+early_param("kstack", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+ code_bytes = simple_strtoul(s, NULL, 0);
+ if (code_bytes > 8192)
+ code_bytes = 8192;
+
+ return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index 24bb5faf5ef..733c4f8d42e 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -95,6 +95,52 @@ static void __init nvidia_bugs(int num, int slot, int func)
}
+static u32 ati_ixp4x0_rev(int num, int slot, int func)
+{
+ u32 d;
+ u8 b;
+
+ b = read_pci_config_byte(num, slot, func, 0xac);
+ b &= ~(1<<5);
+ write_pci_config_byte(num, slot, func, 0xac, b);
+
+ d = read_pci_config(num, slot, func, 0x70);
+ d |= 1<<8;
+ write_pci_config(num, slot, func, 0x70, d);
+
+ d = read_pci_config(num, slot, func, 0x8);
+ d &= 0xff;
+ return d;
+}
+
+static void __init ati_bugs(int num, int slot, int func)
+{
+#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
+ u32 d;
+ u8 b;
+
+ if (acpi_use_timer_override)
+ return;
+
+ d = ati_ixp4x0_rev(num, slot, func);
+ if (d < 0x82)
+ acpi_skip_timer_override = 1;
+ else {
+ /* check for IRQ0 interrupt swap */
+ outb(0x72, 0xcd6); b = inb(0xcd7);
+ if (!(b & 0x2))
+ acpi_skip_timer_override = 1;
+ }
+
+ if (acpi_skip_timer_override) {
+ printk(KERN_INFO "SB4X0 revision 0x%x\n", d);
+ printk(KERN_INFO "Ignoring ACPI timer override.\n");
+ printk(KERN_INFO "If you got timer trouble "
+ "try acpi_use_timer_override\n");
+ }
+#endif
+}
+
#ifdef CONFIG_DMAR
static void __init intel_g33_dmar(int num, int slot, int func)
{
@@ -128,6 +174,8 @@ static struct chipset early_qrk[] __initdata = {
PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
+ PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
#ifdef CONFIG_DMAR
{ PCI_VENDOR_ID_INTEL, 0x29c0,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index ff9e7350da5..34ad997d383 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -3,11 +3,19 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/screen_info.h>
+#include <linux/usb/ch9.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/errno.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/fcntl.h>
#include <asm/setup.h>
#include <xen/hvc-console.h>
+#include <asm/pci-direct.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#include <linux/usb/ehci_def.h>
/* Simple VGA output */
#define VGABASE (__ISA_IO_base + 0xb8000)
@@ -78,6 +86,7 @@ static int early_serial_base = 0x3f8; /* ttyS0 */
static int early_serial_putc(unsigned char ch)
{
unsigned timeout = 0xffff;
+
while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
cpu_relax();
outb(ch, early_serial_base + TXR);
@@ -111,7 +120,7 @@ static __init void early_serial_init(char *s)
if (!strncmp(s, "0x", 2)) {
early_serial_base = simple_strtoul(s, &e, 16);
} else {
- static int bases[] = { 0x3f8, 0x2f8 };
+ static const int __initconst bases[] = { 0x3f8, 0x2f8 };
if (!strncmp(s, "ttyS", 4))
s += 4;
@@ -151,6 +160,721 @@ static struct console early_serial_console = {
.index = -1,
};
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+
+static struct ehci_caps __iomem *ehci_caps;
+static struct ehci_regs __iomem *ehci_regs;
+static struct ehci_dbg_port __iomem *ehci_debug;
+static unsigned int dbgp_endpoint_out;
+
+struct ehci_dev {
+ u32 bus;
+ u32 slot;
+ u32 func;
+};
+
+static struct ehci_dev ehci_dev;
+
+#define USB_DEBUG_DEVNUM 127
+
+#define DBGP_DATA_TOGGLE 0x8800
+
+static inline u32 dbgp_pid_update(u32 x, u32 tok)
+{
+ return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
+}
+
+static inline u32 dbgp_len_update(u32 x, u32 len)
+{
+ return (x & ~0x0f) | (len & 0x0f);
+}
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+
+/* token */
+#define USB_PID_OUT 0xe1
+#define USB_PID_IN 0x69
+#define USB_PID_SOF 0xa5
+#define USB_PID_SETUP 0x2d
+/* handshake */
+#define USB_PID_ACK 0xd2
+#define USB_PID_NAK 0x5a
+#define USB_PID_STALL 0x1e
+#define USB_PID_NYET 0x96
+/* data */
+#define USB_PID_DATA0 0xc3
+#define USB_PID_DATA1 0x4b
+#define USB_PID_DATA2 0x87
+#define USB_PID_MDATA 0x0f
+/* Special */
+#define USB_PID_PREAMBLE 0x3c
+#define USB_PID_ERR 0x3c
+#define USB_PID_SPLIT 0x78
+#define USB_PID_PING 0xb4
+#define USB_PID_UNDEF_0 0xf0
+
+#define USB_PID_DATA_TOGGLE 0x88
+#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
+
+#define PCI_CAP_ID_EHCI_DEBUG 0xa
+
+#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
+#define HUB_SHORT_RESET_TIME 10
+#define HUB_LONG_RESET_TIME 200
+#define HUB_RESET_TIMEOUT 500
+
+#define DBGP_MAX_PACKET 8
+
+static int dbgp_wait_until_complete(void)
+{
+ u32 ctrl;
+ int loop = 0x100000;
+
+ do {
+ ctrl = readl(&ehci_debug->control);
+ /* Stop when the transaction is finished */
+ if (ctrl & DBGP_DONE)
+ break;
+ } while (--loop > 0);
+
+ if (!loop)
+ return -1;
+
+ /*
+ * Now that we have observed the completed transaction,
+ * clear the done bit.
+ */
+ writel(ctrl | DBGP_DONE, &ehci_debug->control);
+ return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
+}
+
+static void dbgp_mdelay(int ms)
+{
+ int i;
+
+ while (ms--) {
+ for (i = 0; i < 1000; i++)
+ outb(0x1, 0x80);
+ }
+}
+
+static void dbgp_breath(void)
+{
+ /* Sleep to give the debug port a chance to breathe */
+}
+
+static int dbgp_wait_until_done(unsigned ctrl)
+{
+ u32 pids, lpid;
+ int ret;
+ int loop = 3;
+
+retry:
+ writel(ctrl | DBGP_GO, &ehci_debug->control);
+ ret = dbgp_wait_until_complete();
+ pids = readl(&ehci_debug->pids);
+ lpid = DBGP_PID_GET(pids);
+
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If the port is getting full or it has dropped data
+ * start pacing ourselves, not necessary but it's friendly.
+ */
+ if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
+ dbgp_breath();
+
+ /* If I get a NACK reissue the transmission */
+ if (lpid == USB_PID_NAK) {
+ if (--loop > 0)
+ goto retry;
+ }
+
+ return ret;
+}
+
+static void dbgp_set_data(const void *buf, int size)
+{
+ const unsigned char *bytes = buf;
+ u32 lo, hi;
+ int i;
+
+ lo = hi = 0;
+ for (i = 0; i < 4 && i < size; i++)
+ lo |= bytes[i] << (8*i);
+ for (; i < 8 && i < size; i++)
+ hi |= bytes[i] << (8*(i - 4));
+ writel(lo, &ehci_debug->data03);
+ writel(hi, &ehci_debug->data47);
+}
+
+static void dbgp_get_data(void *buf, int size)
+{
+ unsigned char *bytes = buf;
+ u32 lo, hi;
+ int i;
+
+ lo = readl(&ehci_debug->data03);
+ hi = readl(&ehci_debug->data47);
+ for (i = 0; i < 4 && i < size; i++)
+ bytes[i] = (lo >> (8*i)) & 0xff;
+ for (; i < 8 && i < size; i++)
+ bytes[i] = (hi >> (8*(i - 4))) & 0xff;
+}
+
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
+ const char *bytes, int size)
+{
+ u32 pids, addr, ctrl;
+ int ret;
+
+ if (size > DBGP_MAX_PACKET)
+ return -1;
+
+ addr = DBGP_EPADDR(devnum, endpoint);
+
+ pids = readl(&ehci_debug->pids);
+ pids = dbgp_pid_update(pids, USB_PID_OUT);
+
+ ctrl = readl(&ehci_debug->control);
+ ctrl = dbgp_len_update(ctrl, size);
+ ctrl |= DBGP_OUT;
+ ctrl |= DBGP_GO;
+
+ dbgp_set_data(bytes, size);
+ writel(addr, &ehci_debug->address);
+ writel(pids, &ehci_debug->pids);
+
+ ret = dbgp_wait_until_done(ctrl);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
+ int size)
+{
+ u32 pids, addr, ctrl;
+ int ret;
+
+ if (size > DBGP_MAX_PACKET)
+ return -1;
+
+ addr = DBGP_EPADDR(devnum, endpoint);
+
+ pids = readl(&ehci_debug->pids);
+ pids = dbgp_pid_update(pids, USB_PID_IN);
+
+ ctrl = readl(&ehci_debug->control);
+ ctrl = dbgp_len_update(ctrl, size);
+ ctrl &= ~DBGP_OUT;
+ ctrl |= DBGP_GO;
+
+ writel(addr, &ehci_debug->address);
+ writel(pids, &ehci_debug->pids);
+ ret = dbgp_wait_until_done(ctrl);
+ if (ret < 0)
+ return ret;
+
+ if (size > ret)
+ size = ret;
+ dbgp_get_data(data, size);
+ return ret;
+}
+
+static int dbgp_control_msg(unsigned devnum, int requesttype, int request,
+ int value, int index, void *data, int size)
+{
+ u32 pids, addr, ctrl;
+ struct usb_ctrlrequest req;
+ int read;
+ int ret;
+
+ read = (requesttype & USB_DIR_IN) != 0;
+ if (size > (read ? DBGP_MAX_PACKET:0))
+ return -1;
+
+ /* Compute the control message */
+ req.bRequestType = requesttype;
+ req.bRequest = request;
+ req.wValue = cpu_to_le16(value);
+ req.wIndex = cpu_to_le16(index);
+ req.wLength = cpu_to_le16(size);
+
+ pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
+ addr = DBGP_EPADDR(devnum, 0);
+
+ ctrl = readl(&ehci_debug->control);
+ ctrl = dbgp_len_update(ctrl, sizeof(req));
+ ctrl |= DBGP_OUT;
+ ctrl |= DBGP_GO;
+
+ /* Send the setup message */
+ dbgp_set_data(&req, sizeof(req));
+ writel(addr, &ehci_debug->address);
+ writel(pids, &ehci_debug->pids);
+ ret = dbgp_wait_until_done(ctrl);
+ if (ret < 0)
+ return ret;
+
+ /* Read the result */
+ return dbgp_bulk_read(devnum, 0, data, size);
+}
+
+
+/* Find a PCI capability */
+static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
+{
+ u8 pos;
+ int bytes;
+
+ if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
+ PCI_STATUS_CAP_LIST))
+ return 0;
+
+ pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
+ for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
+ u8 id;
+
+ pos &= ~3;
+ id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+
+ pos = read_pci_config_byte(num, slot, func,
+ pos+PCI_CAP_LIST_NEXT);
+ }
+ return 0;
+}
+
+static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func)
+{
+ u32 class;
+
+ class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+ if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
+ return 0;
+
+ return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
+}
+
+static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
+{
+ u32 bus, slot, func;
+
+ for (bus = 0; bus < 256; bus++) {
+ for (slot = 0; slot < 32; slot++) {
+ for (func = 0; func < 8; func++) {
+ unsigned cap;
+
+ cap = __find_dbgp(bus, slot, func);
+
+ if (!cap)
+ continue;
+ if (ehci_num-- != 0)
+ continue;
+ *rbus = bus;
+ *rslot = slot;
+ *rfunc = func;
+ return cap;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ehci_reset_port(int port)
+{
+ u32 portsc;
+ u32 delay_time, delay;
+ int loop;
+
+ /* Reset the usb debug port */
+ portsc = readl(&ehci_regs->port_status[port - 1]);
+ portsc &= ~PORT_PE;
+ portsc |= PORT_RESET;
+ writel(portsc, &ehci_regs->port_status[port - 1]);
+
+ delay = HUB_ROOT_RESET_TIME;
+ for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
+ delay_time += delay) {
+ dbgp_mdelay(delay);
+
+ portsc = readl(&ehci_regs->port_status[port - 1]);
+ if (portsc & PORT_RESET) {
+ /* force reset to complete */
+ loop = 2;
+ writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
+ &ehci_regs->port_status[port - 1]);
+ do {
+ portsc = readl(&ehci_regs->port_status[port-1]);
+ } while ((portsc & PORT_RESET) && (--loop > 0));
+ }
+
+ /* Device went away? */
+ if (!(portsc & PORT_CONNECT))
+ return -ENOTCONN;
+
+ /* bomb out completely if something weird happend */
+ if ((portsc & PORT_CSC))
+ return -EINVAL;
+
+ /* If we've finished resetting, then break out of the loop */
+ if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static int ehci_wait_for_port(int port)
+{
+ u32 status;
+ int ret, reps;
+
+ for (reps = 0; reps < 3; reps++) {
+ dbgp_mdelay(100);
+ status = readl(&ehci_regs->status);
+ if (status & STS_PCD) {
+ ret = ehci_reset_port(port);
+ if (ret == 0)
+ return 0;
+ }
+ }
+ return -ENOTCONN;
+}
+
+#ifdef DBGP_DEBUG
+# define dbgp_printk early_printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
+typedef void (*set_debug_port_t)(int port);
+
+static void default_set_debug_port(int port)
+{
+}
+
+static set_debug_port_t set_debug_port = default_set_debug_port;
+
+static void nvidia_set_debug_port(int port)
+{
+ u32 dword;
+ dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+ 0x74);
+ dword &= ~(0x0f<<12);
+ dword |= ((port & 0x0f)<<12);
+ write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74,
+ dword);
+ dbgp_printk("set debug port to %d\n", port);
+}
+
+static void __init detect_set_debug_port(void)
+{
+ u32 vendorid;
+
+ vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+ 0x00);
+
+ if ((vendorid & 0xffff) == 0x10de) {
+ dbgp_printk("using nvidia set_debug_port\n");
+ set_debug_port = nvidia_set_debug_port;
+ }
+}
+
+static int __init ehci_setup(void)
+{
+ struct usb_debug_descriptor dbgp_desc;
+ u32 cmd, ctrl, status, portsc, hcs_params;
+ u32 debug_port, new_debug_port = 0, n_ports;
+ u32 devnum;
+ int ret, i;
+ int loop;
+ int port_map_tried;
+ int playtimes = 3;
+
+try_next_time:
+ port_map_tried = 0;
+
+try_next_port:
+
+ hcs_params = readl(&ehci_caps->hcs_params);
+ debug_port = HCS_DEBUG_PORT(hcs_params);
+ n_ports = HCS_N_PORTS(hcs_params);
+
+ dbgp_printk("debug_port: %d\n", debug_port);
+ dbgp_printk("n_ports: %d\n", n_ports);
+
+ for (i = 1; i <= n_ports; i++) {
+ portsc = readl(&ehci_regs->port_status[i-1]);
+ dbgp_printk("portstatus%d: %08x\n", i, portsc);
+ }
+
+ if (port_map_tried && (new_debug_port != debug_port)) {
+ if (--playtimes) {
+ set_debug_port(new_debug_port);
+ goto try_next_time;
+ }
+ return -1;
+ }
+
+ loop = 10;
+ /* Reset the EHCI controller */
+ cmd = readl(&ehci_regs->command);
+ cmd |= CMD_RESET;
+ writel(cmd, &ehci_regs->command);
+ do {
+ cmd = readl(&ehci_regs->command);
+ } while ((cmd & CMD_RESET) && (--loop > 0));
+
+ if (!loop) {
+ dbgp_printk("can not reset ehci\n");
+ return -1;
+ }
+ dbgp_printk("ehci reset done\n");
+
+ /* Claim ownership, but do not enable yet */
+ ctrl = readl(&ehci_debug->control);
+ ctrl |= DBGP_OWNER;
+ ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
+ writel(ctrl, &ehci_debug->control);
+
+ /* Start the ehci running */
+ cmd = readl(&ehci_regs->command);
+ cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
+ cmd |= CMD_RUN;
+ writel(cmd, &ehci_regs->command);
+
+ /* Ensure everything is routed to the EHCI */
+ writel(FLAG_CF, &ehci_regs->configured_flag);
+
+ /* Wait until the controller is no longer halted */
+ loop = 10;
+ do {
+ status = readl(&ehci_regs->status);
+ } while ((status & STS_HALT) && (--loop > 0));
+
+ if (!loop) {
+ dbgp_printk("ehci can be started\n");
+ return -1;
+ }
+ dbgp_printk("ehci started\n");
+
+ /* Wait for a device to show up in the debug port */
+ ret = ehci_wait_for_port(debug_port);
+ if (ret < 0) {
+ dbgp_printk("No device found in debug port\n");
+ goto next_debug_port;
+ }
+ dbgp_printk("ehci wait for port done\n");
+
+ /* Enable the debug port */
+ ctrl = readl(&ehci_debug->control);
+ ctrl |= DBGP_CLAIM;
+ writel(ctrl, &ehci_debug->control);
+ ctrl = readl(&ehci_debug->control);
+ if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
+ dbgp_printk("No device in debug port\n");
+ writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
+ goto err;
+ }
+ dbgp_printk("debug ported enabled\n");
+
+ /* Completely transfer the debug device to the debug controller */
+ portsc = readl(&ehci_regs->port_status[debug_port - 1]);
+ portsc &= ~PORT_PE;
+ writel(portsc, &ehci_regs->port_status[debug_port - 1]);
+
+ dbgp_mdelay(100);
+
+ /* Find the debug device and make it device number 127 */
+ for (devnum = 0; devnum <= 127; devnum++) {
+ ret = dbgp_control_msg(devnum,
+ USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
+ &dbgp_desc, sizeof(dbgp_desc));
+ if (ret > 0)
+ break;
+ }
+ if (devnum > 127) {
+ dbgp_printk("Could not find attached debug device\n");
+ goto err;
+ }
+ if (ret < 0) {
+ dbgp_printk("Attached device is not a debug device\n");
+ goto err;
+ }
+ dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
+
+ /* Move the device to 127 if it isn't already there */
+ if (devnum != USB_DEBUG_DEVNUM) {
+ ret = dbgp_control_msg(devnum,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
+ if (ret < 0) {
+ dbgp_printk("Could not move attached device to %d\n",
+ USB_DEBUG_DEVNUM);
+ goto err;
+ }
+ devnum = USB_DEBUG_DEVNUM;
+ dbgp_printk("debug device renamed to 127\n");
+ }
+
+ /* Enable the debug interface */
+ ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
+ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
+ if (ret < 0) {
+ dbgp_printk(" Could not enable the debug device\n");
+ goto err;
+ }
+ dbgp_printk("debug interface enabled\n");
+
+ /* Perform a small write to get the even/odd data state in sync
+ */
+ ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1);
+ if (ret < 0) {
+ dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
+ goto err;
+ }
+ dbgp_printk("small write doned\n");
+
+ return 0;
+err:
+ /* Things didn't work so remove my claim */
+ ctrl = readl(&ehci_debug->control);
+ ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
+ writel(ctrl, &ehci_debug->control);
+ return -1;
+
+next_debug_port:
+ port_map_tried |= (1<<(debug_port - 1));
+ new_debug_port = ((debug_port-1+1)%n_ports) + 1;
+ if (port_map_tried != ((1<<n_ports) - 1)) {
+ set_debug_port(new_debug_port);
+ goto try_next_port;
+ }
+ if (--playtimes) {
+ set_debug_port(new_debug_port);
+ goto try_next_time;
+ }
+
+ return -1;
+}
+
+static int __init early_dbgp_init(char *s)
+{
+ u32 debug_port, bar, offset;
+ u32 bus, slot, func, cap;
+ void __iomem *ehci_bar;
+ u32 dbgp_num;
+ u32 bar_val;
+ char *e;
+ int ret;
+ u8 byte;
+
+ if (!early_pci_allowed())
+ return -1;
+
+ dbgp_num = 0;
+ if (*s)
+ dbgp_num = simple_strtoul(s, &e, 10);
+ dbgp_printk("dbgp_num: %d\n", dbgp_num);
+
+ cap = find_dbgp(dbgp_num, &bus, &slot, &func);
+ if (!cap)
+ return -1;
+
+ dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot,
+ func);
+
+ debug_port = read_pci_config(bus, slot, func, cap);
+ bar = (debug_port >> 29) & 0x7;
+ bar = (bar * 4) + 0xc;
+ offset = (debug_port >> 16) & 0xfff;
+ dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
+ if (bar != PCI_BASE_ADDRESS_0) {
+ dbgp_printk("only debug ports on bar 1 handled.\n");
+
+ return -1;
+ }
+
+ bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+ dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset);
+ if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
+ dbgp_printk("only simple 32bit mmio bars supported\n");
+
+ return -1;
+ }
+
+ /* double check if the mem space is enabled */
+ byte = read_pci_config_byte(bus, slot, func, 0x04);
+ if (!(byte & 0x2)) {
+ byte |= 0x02;
+ write_pci_config_byte(bus, slot, func, 0x04, byte);
+ dbgp_printk("mmio for ehci enabled\n");
+ }
+
+ /*
+ * FIXME I don't have the bar size so just guess PAGE_SIZE is more
+ * than enough. 1K is the biggest I have seen.
+ */
+ set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
+ ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+ ehci_bar += bar_val & ~PAGE_MASK;
+ dbgp_printk("ehci_bar: %p\n", ehci_bar);
+
+ ehci_caps = ehci_bar;
+ ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+ ehci_debug = ehci_bar + offset;
+ ehci_dev.bus = bus;
+ ehci_dev.slot = slot;
+ ehci_dev.func = func;
+
+ detect_set_debug_port();
+
+ ret = ehci_setup();
+ if (ret < 0) {
+ dbgp_printk("ehci_setup failed\n");
+ ehci_debug = NULL;
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static void early_dbgp_write(struct console *con, const char *str, u32 n)
+{
+ int chunk, ret;
+
+ if (!ehci_debug)
+ return;
+ while (n > 0) {
+ chunk = n;
+ if (chunk > DBGP_MAX_PACKET)
+ chunk = DBGP_MAX_PACKET;
+ ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
+ dbgp_endpoint_out, str, chunk);
+ str += chunk;
+ n -= chunk;
+ }
+}
+
+static struct console early_dbgp_console = {
+ .name = "earlydbg",
+ .write = early_dbgp_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+#endif
+
/* Console interface to a host file on AMD's SimNow! */
static int simnow_fd;
@@ -165,6 +889,7 @@ enum {
static noinline long simnow(long cmd, long a, long b, long c)
{
long ret;
+
asm volatile("cpuid" :
"=a" (ret) :
"b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
@@ -174,6 +899,7 @@ static noinline long simnow(long cmd, long a, long b, long c)
static void __init simnow_init(char *str)
{
char *fn = "klog";
+
if (*str == '=')
fn = ++str;
/* error ignored */
@@ -194,7 +920,7 @@ static struct console simnow_console = {
/* Direct interface for emergencies */
static struct console *early_console = &early_vga_console;
-static int early_console_initialized;
+static int __initdata early_console_initialized;
asmlinkage void early_printk(const char *fmt, ...)
{
@@ -208,10 +934,11 @@ asmlinkage void early_printk(const char *fmt, ...)
va_end(ap);
}
-static int __initdata keep_early;
static int __init setup_early_printk(char *buf)
{
+ int keep_early;
+
if (!buf)
return 0;
@@ -219,8 +946,7 @@ static int __init setup_early_printk(char *buf)
return 0;
early_console_initialized = 1;
- if (strstr(buf, "keep"))
- keep_early = 1;
+ keep_early = (strstr(buf, "keep") != NULL);
if (!strncmp(buf, "serial", 6)) {
early_serial_init(buf + 6);
@@ -238,6 +964,17 @@ static int __init setup_early_printk(char *buf)
simnow_init(buf + 6);
early_console = &simnow_console;
keep_early = 1;
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+ } else if (!strncmp(buf, "dbgp", 4)) {
+ if (early_dbgp_init(buf+4) < 0)
+ return 0;
+ early_console = &early_dbgp_console;
+ /*
+ * usb subsys will reset ehci controller, so don't keep
+ * that early console
+ */
+ keep_early = 0;
+#endif
#ifdef CONFIG_HVC_XEN
} else if (!strncmp(buf, "xen", 3)) {
early_console = &xenboot_console;
@@ -251,4 +988,5 @@ static int __init setup_early_printk(char *buf)
register_console(early_console);
return 0;
}
+
early_param("earlyprintk", setup_early_printk);
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 109792bc7cf..b21fbfaffe3 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -730,6 +730,7 @@ error_code:
movl $(__USER_DS), %ecx
movl %ecx, %ds
movl %ecx, %es
+ TRACE_IRQS_OFF
movl %esp,%eax # pt_regs pointer
call *%edi
jmp ret_from_exception
@@ -760,20 +761,9 @@ ENTRY(device_not_available)
RING0_INT_FRAME
pushl $-1 # mark this as an int
CFI_ADJUST_CFA_OFFSET 4
- SAVE_ALL
- GET_CR0_INTO_EAX
- testl $0x4, %eax # EM (math emulation bit)
- jne device_not_available_emulate
- preempt_stop(CLBR_ANY)
- call math_state_restore
- jmp ret_from_exception
-device_not_available_emulate:
- pushl $0 # temporary storage for ORIG_EIP
+ pushl $do_device_not_available
CFI_ADJUST_CFA_OFFSET 4
- call math_emulate
- addl $4, %esp
- CFI_ADJUST_CFA_OFFSET -4
- jmp ret_from_exception
+ jmp error_code
CFI_ENDPROC
END(device_not_available)
@@ -814,6 +804,7 @@ debug_stack_correct:
pushl $-1 # mark this as an int
CFI_ADJUST_CFA_OFFSET 4
SAVE_ALL
+ TRACE_IRQS_OFF
xorl %edx,%edx # error code 0
movl %esp,%eax # pt_regs pointer
call do_debug
@@ -858,6 +849,7 @@ nmi_stack_correct:
pushl %eax
CFI_ADJUST_CFA_OFFSET 4
SAVE_ALL
+ TRACE_IRQS_OFF
xorl %edx,%edx # zero error code
movl %esp,%eax # pt_regs pointer
call do_nmi
@@ -898,6 +890,7 @@ nmi_espfix_stack:
pushl %eax
CFI_ADJUST_CFA_OFFSET 4
SAVE_ALL
+ TRACE_IRQS_OFF
FIXUP_ESPFIX_STACK # %eax == %esp
xorl %edx,%edx # zero error code
call do_nmi
@@ -928,6 +921,7 @@ KPROBE_ENTRY(int3)
pushl $-1 # mark this as an int
CFI_ADJUST_CFA_OFFSET 4
SAVE_ALL
+ TRACE_IRQS_OFF
xorl %edx,%edx # zero error code
movl %esp,%eax # pt_regs pointer
call do_int3
@@ -1030,7 +1024,7 @@ ENTRY(machine_check)
RING0_INT_FRAME
pushl $0
CFI_ADJUST_CFA_OFFSET 4
- pushl machine_check_vector
+ pushl $do_machine_check
CFI_ADJUST_CFA_OFFSET 4
jmp error_code
CFI_ENDPROC
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index cf3a0b2d005..1db6ce4314e 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -667,6 +667,13 @@ END(stub_rt_sigreturn)
SAVE_ARGS
leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
pushq %rbp
+ /*
+ * Save rbp twice: One is for marking the stack frame, as usual, and the
+ * other, to fill pt_regs properly. This is because bx comes right
+ * before the last saved register in that structure, and not bp. If the
+ * base pointer were in the place bx is today, this would not be needed.
+ */
+ movq %rbp, -8(%rsp)
CFI_ADJUST_CFA_OFFSET 8
CFI_REL_OFFSET rbp, 0
movq %rsp,%rbp
@@ -932,6 +939,9 @@ END(spurious_interrupt)
.if \ist
movq %gs:pda_data_offset, %rbp
.endif
+ .if \irqtrace
+ TRACE_IRQS_OFF
+ .endif
movq %rsp,%rdi
movq ORIG_RAX(%rsp),%rsi
movq $-1,ORIG_RAX(%rsp)
@@ -1058,7 +1068,8 @@ KPROBE_ENTRY(error_entry)
je error_kernelspace
error_swapgs:
SWAPGS
-error_sti:
+error_sti:
+ TRACE_IRQS_OFF
movq %rdi,RDI(%rsp)
CFI_REL_OFFSET rdi,RDI
movq %rsp,%rdi
@@ -1232,7 +1243,7 @@ ENTRY(simd_coprocessor_error)
END(simd_coprocessor_error)
ENTRY(device_not_available)
- zeroentry math_state_restore
+ zeroentry do_device_not_available
END(device_not_available)
/* runs on exception stack */
diff --git a/arch/x86/kernel/es7000_32.c b/arch/x86/kernel/es7000_32.c
index 849e5cd485b..f454c78fcef 100644
--- a/arch/x86/kernel/es7000_32.c
+++ b/arch/x86/kernel/es7000_32.c
@@ -109,6 +109,7 @@ struct oem_table {
};
extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
#endif
struct mip_reg {
@@ -243,21 +244,38 @@ parse_unisys_oem (char *oemptr)
}
#ifdef CONFIG_ACPI
-int __init
-find_unisys_acpi_oem_table(unsigned long *oem_addr)
+static unsigned long oem_addrX;
+static unsigned long oem_size;
+int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
{
struct acpi_table_header *header = NULL;
int i = 0;
- while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
+ acpi_size tbl_size;
+
+ while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) {
if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
struct oem_table *t = (struct oem_table *)header;
- *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
- t->OEMTableSize);
+
+ oem_addrX = t->OEMTableAddr;
+ oem_size = t->OEMTableSize;
+ early_acpi_os_unmap_memory(header, tbl_size);
+
+ *oem_addr = (unsigned long)__acpi_map_table(oem_addrX,
+ oem_size);
return 0;
}
+ early_acpi_os_unmap_memory(header, tbl_size);
}
return -1;
}
+
+void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
+{
+ if (!oem_addr)
+ return;
+
+ __acpi_unmap_table((char *)oem_addr, oem_size);
+}
#endif
static void
diff --git a/arch/x86/kernel/genx2apic_uv_x.c b/arch/x86/kernel/genx2apic_uv_x.c
index ae2ffc8a400..33581d94a90 100644
--- a/arch/x86/kernel/genx2apic_uv_x.c
+++ b/arch/x86/kernel/genx2apic_uv_x.c
@@ -114,7 +114,7 @@ static void uv_send_IPI_one(int cpu, int vector)
unsigned long val, apicid, lapicid;
int pnode;
- apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */
+ apicid = per_cpu(x86_cpu_to_apicid, cpu);
lapicid = apicid & 0x3f; /* ZZZ macro needed */
pnode = uv_apicid_to_pnode(apicid);
val =
@@ -202,12 +202,10 @@ static unsigned int phys_pkg_id(int index_msb)
return uv_read_apic_id() >> index_msb;
}
-#ifdef ZZZ /* Needs x2apic patch */
static void uv_send_IPI_self(int vector)
{
apic_write(APIC_SELF_IPI, vector);
}
-#endif
struct genapic apic_x2apic_uv_x = {
.name = "UV large system",
@@ -215,15 +213,15 @@ struct genapic apic_x2apic_uv_x = {
.int_delivery_mode = dest_Fixed,
.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
.target_cpus = uv_target_cpus,
- .vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */
+ .vector_allocation_domain = uv_vector_allocation_domain,
.apic_id_registered = uv_apic_id_registered,
.init_apic_ldr = uv_init_apic_ldr,
.send_IPI_all = uv_send_IPI_all,
.send_IPI_allbutself = uv_send_IPI_allbutself,
.send_IPI_mask = uv_send_IPI_mask,
- /* ZZZ.send_IPI_self = uv_send_IPI_self, */
+ .send_IPI_self = uv_send_IPI_self,
.cpu_mask_to_apicid = uv_cpu_mask_to_apicid,
- .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */
+ .phys_pkg_id = phys_pkg_id,
.get_apic_id = get_apic_id,
.set_apic_id = set_apic_id,
.apic_id_mask = (0xFFFFFFFFu),
@@ -286,12 +284,13 @@ static __init void map_low_mmrs(void)
enum map_type {map_wb, map_uc};
-static __init void map_high(char *id, unsigned long base, int shift, enum map_type map_type)
+static __init void map_high(char *id, unsigned long base, int shift,
+ int max_pnode, enum map_type map_type)
{
unsigned long bytes, paddr;
paddr = base << shift;
- bytes = (1UL << shift);
+ bytes = (1UL << shift) * (max_pnode + 1);
printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
paddr + bytes);
if (map_type == map_uc)
@@ -307,7 +306,7 @@ static __init void map_gru_high(int max_pnode)
gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
if (gru.s.enable)
- map_high("GRU", gru.s.base, shift, map_wb);
+ map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
}
static __init void map_config_high(int max_pnode)
@@ -317,7 +316,7 @@ static __init void map_config_high(int max_pnode)
cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR);
if (cfg.s.enable)
- map_high("CONFIG", cfg.s.base, shift, map_uc);
+ map_high("CONFIG", cfg.s.base, shift, max_pnode, map_uc);
}
static __init void map_mmr_high(int max_pnode)
@@ -327,7 +326,7 @@ static __init void map_mmr_high(int max_pnode)
mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
if (mmr.s.enable)
- map_high("MMR", mmr.s.base, shift, map_uc);
+ map_high("MMR", mmr.s.base, shift, max_pnode, map_uc);
}
static __init void map_mmioh_high(int max_pnode)
@@ -337,7 +336,7 @@ static __init void map_mmioh_high(int max_pnode)
mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
if (mmioh.s.enable)
- map_high("MMIOH", mmioh.s.base, shift, map_uc);
+ map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
}
static __init void uv_rtc_init(void)
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
index 3e66bd364a9..1dcb0f13897 100644
--- a/arch/x86/kernel/head.c
+++ b/arch/x86/kernel/head.c
@@ -35,6 +35,7 @@ void __init reserve_ebda_region(void)
/* start of EBDA area */
ebda_addr = get_bios_ebda();
+ printk(KERN_INFO "BIOS EBDA/lowmem at: %08x/%08x\n", ebda_addr, lowmem);
/* Fixup: bios puts an EBDA in the top 64K segment */
/* of conventional memory, but does not adjust lowmem. */
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 73deaffadd0..acf62fc233d 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -115,13 +115,17 @@ static void hpet_reserve_platform_timers(unsigned long id)
hd.hd_phys_address = hpet_address;
hd.hd_address = hpet;
hd.hd_nirqs = nrtimers;
- hd.hd_flags = HPET_DATA_PLATFORM;
hpet_reserve_timer(&hd, 0);
#ifdef CONFIG_HPET_EMULATE_RTC
hpet_reserve_timer(&hd, 1);
#endif
+ /*
+ * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254
+ * is wrong for i8259!) not the output IRQ. Many BIOS writers
+ * don't bother configuring *any* comparator interrupts.
+ */
hd.hd_irq[0] = HPET_LEGACY_8254;
hd.hd_irq[1] = HPET_LEGACY_RTC;
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 45723f1fe19..1f20608d4ca 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -468,9 +468,23 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
static int save_i387_xsave(void __user *buf)
{
+ struct task_struct *tsk = current;
struct _fpstate_ia32 __user *fx = buf;
int err = 0;
+ /*
+ * For legacy compatible, we always set FP/SSE bits in the bit
+ * vector while saving the state to the user context.
+ * This will enable us capturing any changes(during sigreturn) to
+ * the FP/SSE bits by the legacy applications which don't touch
+ * xstate_bv in the xsave header.
+ *
+ * xsave aware applications can change the xstate_bv in the xsave
+ * header as well as change any contents in the memory layout.
+ * xrestore as part of sigreturn will capture all the changes.
+ */
+ tsk->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
+
if (save_i387_fxsave(fx) < 0)
return -1;
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index a1bec2969c6..02063ae042f 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -1281,8 +1281,8 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
icr = apic_icr_read();
- printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
- printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
+ printk(KERN_DEBUG "... APIC ICR: %08x\n", (u32)icr);
+ printk(KERN_DEBUG "... APIC ICR2: %08x\n", (u32)(icr >> 32));
v = apic_read(APIC_LVTT);
printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c
index 1f26fd9ec4f..5b5be9d43c2 100644
--- a/arch/x86/kernel/irqinit_64.c
+++ b/arch/x86/kernel/irqinit_64.c
@@ -135,7 +135,7 @@ DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
[IRQ15_VECTOR + 1 ... NR_VECTORS - 1] = -1
};
-static void __init init_ISA_irqs (void)
+void __init init_ISA_irqs(void)
{
int i;
@@ -164,22 +164,8 @@ static void __init init_ISA_irqs (void)
void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
-void __init native_init_IRQ(void)
+static void __init smp_intr_init(void)
{
- int i;
-
- init_ISA_irqs();
- /*
- * Cover the whole vector space, no vector can escape
- * us. (some of these will be overridden and become
- * 'special' SMP interrupts)
- */
- for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
- int vector = FIRST_EXTERNAL_VECTOR + i;
- if (vector != IA32_SYSCALL_VECTOR)
- set_intr_gate(vector, interrupt[i]);
- }
-
#ifdef CONFIG_SMP
/*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
@@ -207,6 +193,12 @@ void __init native_init_IRQ(void)
/* Low priority IPI to cleanup after moving an irq */
set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
#endif
+}
+
+static void __init apic_intr_init(void)
+{
+ smp_intr_init();
+
alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
@@ -216,6 +208,25 @@ void __init native_init_IRQ(void)
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+}
+
+void __init native_init_IRQ(void)
+{
+ int i;
+
+ init_ISA_irqs();
+ /*
+ * Cover the whole vector space, no vector can escape
+ * us. (some of these will be overridden and become
+ * 'special' SMP interrupts)
+ */
+ for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
+ int vector = FIRST_EXTERNAL_VECTOR + i;
+ if (vector != IA32_SYSCALL_VECTOR)
+ set_intr_gate(vector, interrupt[i]);
+ }
+
+ apic_intr_init();
if (!acpi_ioapic)
setup_irq(2, &irq2);
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index 0ed5f939b90..eee32b43fee 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -52,6 +52,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
memset(newldt + oldsize * LDT_ENTRY_SIZE, 0,
(mincount - oldsize) * LDT_ENTRY_SIZE);
+ paravirt_alloc_ldt(newldt, mincount);
+
#ifdef CONFIG_X86_64
/* CHECKME: Do we really need this ? */
wmb();
@@ -74,6 +76,7 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
#endif
}
if (oldsize) {
+ paravirt_free_ldt(oldldt, oldsize);
if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE)
vfree(oldldt);
else
@@ -85,10 +88,13 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
{
int err = alloc_ldt(new, old->size, 0);
+ int i;
if (err < 0)
return err;
- memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE);
+
+ for(i = 0; i < old->size; i++)
+ write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
return 0;
}
@@ -125,6 +131,7 @@ void destroy_context(struct mm_struct *mm)
if (mm == current->active_mm)
clear_LDT();
#endif
+ paravirt_free_ldt(mm->context.ldt, mm->context.size);
if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE)
vfree(mm->context.ldt);
else
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
deleted file mode 100644
index 652fa5c38eb..00000000000
--- a/arch/x86/kernel/microcode.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- * Intel CPU Microcode Update Driver for Linux
- *
- * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
- * 2006 Shaohua Li <shaohua.li@intel.com>
- *
- * This driver allows to upgrade microcode on Intel processors
- * belonging to IA-32 family - PentiumPro, Pentium II,
- * Pentium III, Xeon, Pentium 4, etc.
- *
- * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
- * Software Developer's Manual
- * Order Number 253668 or free download from:
- *
- * http://developer.intel.com/design/pentium4/manuals/253668.htm
- *
- * For more information, go to http://www.urbanmyth.org/microcode
- *
- * 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 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Initial release.
- * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added read() support + cleanups.
- * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added 'device trimming' support. open(O_WRONLY) zeroes
- * and frees the saved copy of applied microcode.
- * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Made to use devfs (/dev/cpu/microcode) + cleanups.
- * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Added misc device support (now uses both devfs and misc).
- * Added MICROCODE_IOCFREE ioctl to clear memory.
- * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Messages for error cases (non Intel & no suitable microcode).
- * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
- * Removed ->release(). Removed exclusive open and status bitmap.
- * Added microcode_rwsem to serialize read()/write()/ioctl().
- * Removed global kernel lock usage.
- * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
- * Write 0 to 0x8B msr and then cpuid before reading revision,
- * so that it works even if there were no update done by the
- * BIOS. Otherwise, reading from 0x8B gives junk (which happened
- * to be 0 on my machine which is why it worked even when I
- * disabled update by the BIOS)
- * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
- * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>
- * Intel Pentium 4 processor support and bugfixes.
- * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
- * Bugfix for HT (Hyper-Threading) enabled processors
- * whereby processor resources are shared by all logical processors
- * in a single CPU package.
- * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>,
- * Serialize updates as required on HT processors due to speculative
- * nature of implementation.
- * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
- * Fix the panic when writing zero-length microcode chunk.
- * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
- * Jun Nakajima <jun.nakajima@intel.com>
- * Support for the microcode updates in the new format.
- * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
- * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- * because we no longer hold a copy of applied microcode
- * in kernel memory.
- * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
- * Fix sigmatch() macro to handle old CPUs with pf == 0.
- * Thanks to Stuart Swales for pointing out this bug.
- */
-
-//#define DEBUG /* pr_debug */
-#include <linux/capability.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/cpumask.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/cpu.h>
-#include <linux/firmware.h>
-#include <linux/platform_device.h>
-
-#include <asm/msr.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
-MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
-MODULE_LICENSE("GPL");
-
-#define MICROCODE_VERSION "1.14a"
-
-#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
-#define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
-#define EXT_HEADER_SIZE (sizeof (struct extended_sigtable)) /* 20 bytes */
-#define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature)) /* 12 bytes */
-#define DWSIZE (sizeof (u32))
-#define get_totalsize(mc) \
- (((microcode_t *)mc)->hdr.totalsize ? \
- ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
-#define get_datasize(mc) \
- (((microcode_t *)mc)->hdr.datasize ? \
- ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-
-#define sigmatch(s1, s2, p1, p2) \
- (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
-#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-
-/* serialize access to the physical write to MSR 0x79 */
-static DEFINE_SPINLOCK(microcode_update_lock);
-
-/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DEFINE_MUTEX(microcode_mutex);
-
-static struct ucode_cpu_info {
- int valid;
- unsigned int sig;
- unsigned int pf;
- unsigned int rev;
- microcode_t *mc;
-} ucode_cpu_info[NR_CPUS];
-
-static void collect_cpu_info(int cpu_num)
-{
- struct cpuinfo_x86 *c = &cpu_data(cpu_num);
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- unsigned int val[2];
-
- /* We should bind the task to the CPU */
- BUG_ON(raw_smp_processor_id() != cpu_num);
- uci->pf = uci->rev = 0;
- uci->mc = NULL;
- uci->valid = 1;
-
- if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
- cpu_has(c, X86_FEATURE_IA64)) {
- printk(KERN_ERR "microcode: CPU%d not a capable Intel "
- "processor\n", cpu_num);
- uci->valid = 0;
- return;
- }
-
- uci->sig = cpuid_eax(0x00000001);
-
- if ((c->x86_model >= 5) || (c->x86 > 6)) {
- /* get processor flags from MSR 0x17 */
- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
- uci->pf = 1 << ((val[1] >> 18) & 7);
- }
-
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- /* see notes above for revision 1.07. Apparent chip bug */
- sync_core();
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
- pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
- uci->sig, uci->pf, uci->rev);
-}
-
-static inline int microcode_update_match(int cpu_num,
- microcode_header_t *mc_header, int sig, int pf)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
- if (!sigmatch(sig, uci->sig, pf, uci->pf)
- || mc_header->rev <= uci->rev)
- return 0;
- return 1;
-}
-
-static int microcode_sanity_check(void *mc)
-{
- microcode_header_t *mc_header = mc;
- struct extended_sigtable *ext_header = NULL;
- struct extended_signature *ext_sig;
- unsigned long total_size, data_size, ext_table_size;
- int sum, orig_sum, ext_sigcount = 0, i;
-
- total_size = get_totalsize(mc_header);
- data_size = get_datasize(mc_header);
- if (data_size + MC_HEADER_SIZE > total_size) {
- printk(KERN_ERR "microcode: error! "
- "Bad data size in microcode data file\n");
- return -EINVAL;
- }
-
- if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
- printk(KERN_ERR "microcode: error! "
- "Unknown microcode update format\n");
- return -EINVAL;
- }
- ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
- if (ext_table_size) {
- if ((ext_table_size < EXT_HEADER_SIZE)
- || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
- printk(KERN_ERR "microcode: error! "
- "Small exttable size in microcode data file\n");
- return -EINVAL;
- }
- ext_header = mc + MC_HEADER_SIZE + data_size;
- if (ext_table_size != exttable_size(ext_header)) {
- printk(KERN_ERR "microcode: error! "
- "Bad exttable size in microcode data file\n");
- return -EFAULT;
- }
- ext_sigcount = ext_header->count;
- }
-
- /* check extended table checksum */
- if (ext_table_size) {
- int ext_table_sum = 0;
- int *ext_tablep = (int *)ext_header;
-
- i = ext_table_size / DWSIZE;
- while (i--)
- ext_table_sum += ext_tablep[i];
- if (ext_table_sum) {
- printk(KERN_WARNING "microcode: aborting, "
- "bad extended signature table checksum\n");
- return -EINVAL;
- }
- }
-
- /* calculate the checksum */
- orig_sum = 0;
- i = (MC_HEADER_SIZE + data_size) / DWSIZE;
- while (i--)
- orig_sum += ((int *)mc)[i];
- if (orig_sum) {
- printk(KERN_ERR "microcode: aborting, bad checksum\n");
- return -EINVAL;
- }
- if (!ext_table_size)
- return 0;
- /* check extended signature checksum */
- for (i = 0; i < ext_sigcount; i++) {
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
- EXT_SIGNATURE_SIZE * i;
- sum = orig_sum
- - (mc_header->sig + mc_header->pf + mc_header->cksum)
- + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
- if (sum) {
- printk(KERN_ERR "microcode: aborting, bad checksum\n");
- return -EINVAL;
- }
- }
- return 0;
-}
-
-/*
- * return 0 - no update found
- * return 1 - found update
- * return < 0 - error
- */
-static int get_maching_microcode(void *mc, int cpu)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
- microcode_header_t *mc_header = mc;
- struct extended_sigtable *ext_header;
- unsigned long total_size = get_totalsize(mc_header);
- int ext_sigcount, i;
- struct extended_signature *ext_sig;
- void *new_mc;
-
- if (microcode_update_match(cpu, mc_header,
- mc_header->sig, mc_header->pf))
- goto find;
-
- if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
- return 0;
-
- ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
- ext_sigcount = ext_header->count;
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
- for (i = 0; i < ext_sigcount; i++) {
- if (microcode_update_match(cpu, mc_header,
- ext_sig->sig, ext_sig->pf))
- goto find;
- ext_sig++;
- }
- return 0;
-find:
- pr_debug("microcode: CPU%d found a matching microcode update with"
- " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
- new_mc = vmalloc(total_size);
- if (!new_mc) {
- printk(KERN_ERR "microcode: error! Can not allocate memory\n");
- return -ENOMEM;
- }
-
- /* free previous update file */
- vfree(uci->mc);
-
- memcpy(new_mc, mc, total_size);
- uci->mc = new_mc;
- return 1;
-}
-
-static void apply_microcode(int cpu)
-{
- unsigned long flags;
- unsigned int val[2];
- int cpu_num = raw_smp_processor_id();
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
- /* We should bind the task to the CPU */
- BUG_ON(cpu_num != cpu);
-
- if (uci->mc == NULL)
- return;
-
- /* serialize access to the physical write to MSR 0x79 */
- spin_lock_irqsave(&microcode_update_lock, flags);
-
- /* write microcode via MSR 0x79 */
- wrmsr(MSR_IA32_UCODE_WRITE,
- (unsigned long) uci->mc->bits,
- (unsigned long) uci->mc->bits >> 16 >> 16);
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
- /* see notes above for revision 1.07. Apparent chip bug */
- sync_core();
-
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
- spin_unlock_irqrestore(&microcode_update_lock, flags);
- if (val[1] != uci->mc->hdr.rev) {
- printk(KERN_ERR "microcode: CPU%d update from revision "
- "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
- return;
- }
- printk(KERN_INFO "microcode: CPU%d updated from revision "
- "0x%x to 0x%x, date = %08x \n",
- cpu_num, uci->rev, val[1], uci->mc->hdr.date);
- uci->rev = val[1];
-}
-
-#ifdef CONFIG_MICROCODE_OLD_INTERFACE
-static void __user *user_buffer; /* user area microcode data buffer */
-static unsigned int user_buffer_size; /* it's size */
-
-static long get_next_ucode(void **mc, long offset)
-{
- microcode_header_t mc_header;
- unsigned long total_size;
-
- /* No more data */
- if (offset >= user_buffer_size)
- return 0;
- if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- return -EFAULT;
- }
- total_size = get_totalsize(&mc_header);
- if (offset + total_size > user_buffer_size) {
- printk(KERN_ERR "microcode: error! Bad total size in microcode "
- "data file\n");
- return -EINVAL;
- }
- *mc = vmalloc(total_size);
- if (!*mc)
- return -ENOMEM;
- if (copy_from_user(*mc, user_buffer + offset, total_size)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- vfree(*mc);
- return -EFAULT;
- }
- return offset + total_size;
-}
-
-static int do_microcode_update (void)
-{
- long cursor = 0;
- int error = 0;
- void *new_mc = NULL;
- int cpu;
- cpumask_t old;
-
- old = current->cpus_allowed;
-
- while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
- error = microcode_sanity_check(new_mc);
- if (error)
- goto out;
- /*
- * It's possible the data file has multiple matching ucode,
- * lets keep searching till the latest version
- */
- for_each_online_cpu(cpu) {
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- if (!uci->valid)
- continue;
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
- error = get_maching_microcode(new_mc, cpu);
- if (error < 0)
- goto out;
- if (error == 1)
- apply_microcode(cpu);
- }
- vfree(new_mc);
- }
-out:
- if (cursor > 0)
- vfree(new_mc);
- if (cursor < 0)
- error = cursor;
- set_cpus_allowed_ptr(current, &old);
- return error;
-}
-
-static int microcode_open (struct inode *unused1, struct file *unused2)
-{
- cycle_kernel_lock();
- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
-{
- ssize_t ret;
-
- if ((len >> PAGE_SHIFT) > num_physpages) {
- printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
- return -EINVAL;
- }
-
- get_online_cpus();
- mutex_lock(&microcode_mutex);
-
- user_buffer = (void __user *) buf;
- user_buffer_size = (int) len;
-
- ret = do_microcode_update();
- if (!ret)
- ret = (ssize_t)len;
-
- mutex_unlock(&microcode_mutex);
- put_online_cpus();
-
- return ret;
-}
-
-static const struct file_operations microcode_fops = {
- .owner = THIS_MODULE,
- .write = microcode_write,
- .open = microcode_open,
-};
-
-static struct miscdevice microcode_dev = {
- .minor = MICROCODE_MINOR,
- .name = "microcode",
- .fops = &microcode_fops,
-};
-
-static int __init microcode_dev_init (void)
-{
- int error;
-
- error = misc_register(&microcode_dev);
- if (error) {
- printk(KERN_ERR
- "microcode: can't misc_register on minor=%d\n",
- MICROCODE_MINOR);
- return error;
- }
-
- return 0;
-}
-
-static void microcode_dev_exit (void)
-{
- misc_deregister(&microcode_dev);
-}
-
-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
-#else
-#define microcode_dev_init() 0
-#define microcode_dev_exit() do { } while(0)
-#endif
-
-static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
- unsigned long size, long offset)
-{
- microcode_header_t *mc_header;
- unsigned long total_size;
-
- /* No more data */
- if (offset >= size)
- return 0;
- mc_header = (microcode_header_t *)(buf + offset);
- total_size = get_totalsize(mc_header);
-
- if (offset + total_size > size) {
- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
- return -EINVAL;
- }
-
- *mc = vmalloc(total_size);
- if (!*mc) {
- printk(KERN_ERR "microcode: error! Can not allocate memory\n");
- return -ENOMEM;
- }
- memcpy(*mc, buf + offset, total_size);
- return offset + total_size;
-}
-
-/* fake device for request_firmware */
-static struct platform_device *microcode_pdev;
-
-static int cpu_request_microcode(int cpu)
-{
- char name[30];
- struct cpuinfo_x86 *c = &cpu_data(cpu);
- const struct firmware *firmware;
- const u8 *buf;
- unsigned long size;
- long offset = 0;
- int error;
- void *mc;
-
- /* We should bind the task to the CPU */
- BUG_ON(cpu != raw_smp_processor_id());
- sprintf(name,"intel-ucode/%02x-%02x-%02x",
- c->x86, c->x86_model, c->x86_mask);
- error = request_firmware(&firmware, name, &microcode_pdev->dev);
- if (error) {
- pr_debug("microcode: data file %s load failed\n", name);
- return error;
- }
- buf = firmware->data;
- size = firmware->size;
- while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
- > 0) {
- error = microcode_sanity_check(mc);
- if (error)
- break;
- error = get_maching_microcode(mc, cpu);
- if (error < 0)
- break;
- /*
- * It's possible the data file has multiple matching ucode,
- * lets keep searching till the latest version
- */
- if (error == 1) {
- apply_microcode(cpu);
- error = 0;
- }
- vfree(mc);
- }
- if (offset > 0)
- vfree(mc);
- if (offset < 0)
- error = offset;
- release_firmware(firmware);
-
- return error;
-}
-
-static int apply_microcode_check_cpu(int cpu)
-{
- struct cpuinfo_x86 *c = &cpu_data(cpu);
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
- cpumask_t old;
- unsigned int val[2];
- int err = 0;
-
- /* Check if the microcode is available */
- if (!uci->mc)
- return 0;
-
- old = current->cpus_allowed;
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
- /* Check if the microcode we have in memory matches the CPU */
- if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
- cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
- err = -EINVAL;
-
- if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
- /* get processor flags from MSR 0x17 */
- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
- if (uci->pf != (1 << ((val[1] >> 18) & 7)))
- err = -EINVAL;
- }
-
- if (!err) {
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- /* see notes above for revision 1.07. Apparent chip bug */
- sync_core();
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
- if (uci->rev != val[1])
- err = -EINVAL;
- }
-
- if (!err)
- apply_microcode(cpu);
- else
- printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
- " sig=0x%x, pf=0x%x, rev=0x%x\n",
- cpu, uci->sig, uci->pf, uci->rev);
-
- set_cpus_allowed_ptr(current, &old);
- return err;
-}
-
-static void microcode_init_cpu(int cpu, int resume)
-{
- cpumask_t old;
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- old = current->cpus_allowed;
-
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
- mutex_lock(&microcode_mutex);
- collect_cpu_info(cpu);
- if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
- cpu_request_microcode(cpu);
- mutex_unlock(&microcode_mutex);
- set_cpus_allowed_ptr(current, &old);
-}
-
-static void microcode_fini_cpu(int cpu)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- mutex_lock(&microcode_mutex);
- uci->valid = 0;
- vfree(uci->mc);
- uci->mc = NULL;
- mutex_unlock(&microcode_mutex);
-}
-
-static ssize_t reload_store(struct sys_device *dev,
- struct sysdev_attribute *attr,
- const char *buf, size_t sz)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
- char *end;
- unsigned long val = simple_strtoul(buf, &end, 0);
- int err = 0;
- int cpu = dev->id;
-
- if (end == buf)
- return -EINVAL;
- if (val == 1) {
- cpumask_t old = current->cpus_allowed;
-
- get_online_cpus();
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
- mutex_lock(&microcode_mutex);
- if (uci->valid)
- err = cpu_request_microcode(cpu);
- mutex_unlock(&microcode_mutex);
- put_online_cpus();
- set_cpus_allowed_ptr(current, &old);
- }
- if (err)
- return err;
- return sz;
-}
-
-static ssize_t version_show(struct sys_device *dev,
- struct sysdev_attribute *attr, char *buf)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
- return sprintf(buf, "0x%x\n", uci->rev);
-}
-
-static ssize_t pf_show(struct sys_device *dev,
- struct sysdev_attribute *attr, char *buf)
-{
- struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
- return sprintf(buf, "0x%x\n", uci->pf);
-}
-
-static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
-static SYSDEV_ATTR(version, 0400, version_show, NULL);
-static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
-
-static struct attribute *mc_default_attrs[] = {
- &attr_reload.attr,
- &attr_version.attr,
- &attr_processor_flags.attr,
- NULL
-};
-
-static struct attribute_group mc_attr_group = {
- .attrs = mc_default_attrs,
- .name = "microcode",
-};
-
-static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
-{
- int err, cpu = sys_dev->id;
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
- if (!cpu_online(cpu))
- return 0;
-
- pr_debug("microcode: CPU%d added\n", cpu);
- memset(uci, 0, sizeof(*uci));
-
- err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
- if (err)
- return err;
-
- microcode_init_cpu(cpu, resume);
-
- return 0;
-}
-
-static int mc_sysdev_add(struct sys_device *sys_dev)
-{
- return __mc_sysdev_add(sys_dev, 0);
-}
-
-static int mc_sysdev_remove(struct sys_device *sys_dev)
-{
- int cpu = sys_dev->id;
-
- if (!cpu_online(cpu))
- return 0;
-
- pr_debug("microcode: CPU%d removed\n", cpu);
- microcode_fini_cpu(cpu);
- sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
- return 0;
-}
-
-static int mc_sysdev_resume(struct sys_device *dev)
-{
- int cpu = dev->id;
-
- if (!cpu_online(cpu))
- return 0;
- pr_debug("microcode: CPU%d resumed\n", cpu);
- /* only CPU 0 will apply ucode here */
- apply_microcode(0);
- return 0;
-}
-
-static struct sysdev_driver mc_sysdev_driver = {
- .add = mc_sysdev_add,
- .remove = mc_sysdev_remove,
- .resume = mc_sysdev_resume,
-};
-
-static __cpuinit int
-mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
-{
- unsigned int cpu = (unsigned long)hcpu;
- struct sys_device *sys_dev;
-
- sys_dev = get_cpu_sysdev(cpu);
- switch (action) {
- case CPU_UP_CANCELED_FROZEN:
- /* The CPU refused to come up during a system resume */
- microcode_fini_cpu(cpu);
- break;
- case CPU_ONLINE:
- case CPU_DOWN_FAILED:
- mc_sysdev_add(sys_dev);
- break;
- case CPU_ONLINE_FROZEN:
- /* System-wide resume is in progress, try to apply microcode */
- if (apply_microcode_check_cpu(cpu)) {
- /* The application of microcode failed */
- microcode_fini_cpu(cpu);
- __mc_sysdev_add(sys_dev, 1);
- break;
- }
- case CPU_DOWN_FAILED_FROZEN:
- if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
- printk(KERN_ERR "microcode: Failed to create the sysfs "
- "group for CPU%d\n", cpu);
- break;
- case CPU_DOWN_PREPARE:
- mc_sysdev_remove(sys_dev);
- break;
- case CPU_DOWN_PREPARE_FROZEN:
- /* Suspend is in progress, only remove the interface */
- sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
- break;
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata mc_cpu_notifier = {
- .notifier_call = mc_cpu_callback,
-};
-
-static int __init microcode_init (void)
-{
- int error;
-
- printk(KERN_INFO
- "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
-
- error = microcode_dev_init();
- if (error)
- return error;
- microcode_pdev = platform_device_register_simple("microcode", -1,
- NULL, 0);
- if (IS_ERR(microcode_pdev)) {
- microcode_dev_exit();
- return PTR_ERR(microcode_pdev);
- }
-
- get_online_cpus();
- error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
- put_online_cpus();
- if (error) {
- microcode_dev_exit();
- platform_device_unregister(microcode_pdev);
- return error;
- }
-
- register_hotcpu_notifier(&mc_cpu_notifier);
- return 0;
-}
-
-static void __exit microcode_exit (void)
-{
- microcode_dev_exit();
-
- unregister_hotcpu_notifier(&mc_cpu_notifier);
-
- get_online_cpus();
- sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
- put_online_cpus();
-
- platform_device_unregister(microcode_pdev);
-}
-
-module_init(microcode_init)
-module_exit(microcode_exit)
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
new file mode 100644
index 00000000000..7a1f8eeac2c
--- /dev/null
+++ b/arch/x86/kernel/microcode_amd.c
@@ -0,0 +1,435 @@
+/*
+ * AMD CPU Microcode Update Driver for Linux
+ * Copyright (C) 2008 Advanced Micro Devices Inc.
+ *
+ * Author: Peter Oruba <peter.oruba@amd.com>
+ *
+ * Based on work by:
+ * Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *
+ * This driver allows to upgrade microcode on AMD
+ * family 0x10 and 0x11 processors.
+ *
+ * Licensed unter the terms of the GNU General Public
+ * License version 2. See file COPYING for details.
+*/
+
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("AMD Microcode Update Driver");
+MODULE_AUTHOR("Peter Oruba <peter.oruba@amd.com>");
+MODULE_LICENSE("GPL v2");
+
+#define UCODE_MAGIC 0x00414d44
+#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
+#define UCODE_UCODE_TYPE 0x00000001
+
+struct equiv_cpu_entry {
+ unsigned int installed_cpu;
+ unsigned int fixed_errata_mask;
+ unsigned int fixed_errata_compare;
+ unsigned int equiv_cpu;
+};
+
+struct microcode_header_amd {
+ unsigned int data_code;
+ unsigned int patch_id;
+ unsigned char mc_patch_data_id[2];
+ unsigned char mc_patch_data_len;
+ unsigned char init_flag;
+ unsigned int mc_patch_data_checksum;
+ unsigned int nb_dev_id;
+ unsigned int sb_dev_id;
+ unsigned char processor_rev_id[2];
+ unsigned char nb_rev_id;
+ unsigned char sb_rev_id;
+ unsigned char bios_api_rev;
+ unsigned char reserved1[3];
+ unsigned int match_reg[8];
+};
+
+struct microcode_amd {
+ struct microcode_header_amd hdr;
+ unsigned int mpb[0];
+};
+
+#define UCODE_MAX_SIZE (2048)
+#define DEFAULT_UCODE_DATASIZE (896)
+#define MC_HEADER_SIZE (sizeof(struct microcode_header_amd))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define DWSIZE (sizeof(u32))
+/* For now we support a fixed ucode total size only */
+#define get_totalsize(mc) \
+ ((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \
+ + MC_HEADER_SIZE)
+
+/* serialize access to the physical write */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static struct equiv_cpu_entry *equiv_cpu_table;
+
+static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
+{
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+ memset(csig, 0, sizeof(*csig));
+
+ if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
+ printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
+ cpu);
+ return -1;
+ }
+
+ asm volatile("movl %1, %%ecx; rdmsr"
+ : "=a" (csig->rev)
+ : "i" (0x0000008B) : "ecx");
+
+ printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n",
+ csig->rev);
+
+ return 0;
+}
+
+static int get_matching_microcode(int cpu, void *mc, int rev)
+{
+ struct microcode_header_amd *mc_header = mc;
+ struct pci_dev *nb_pci_dev, *sb_pci_dev;
+ unsigned int current_cpu_id;
+ unsigned int equiv_cpu_id = 0x00;
+ unsigned int i = 0;
+
+ BUG_ON(equiv_cpu_table == NULL);
+ current_cpu_id = cpuid_eax(0x00000001);
+
+ while (equiv_cpu_table[i].installed_cpu != 0) {
+ if (current_cpu_id == equiv_cpu_table[i].installed_cpu) {
+ equiv_cpu_id = equiv_cpu_table[i].equiv_cpu;
+ break;
+ }
+ i++;
+ }
+
+ if (!equiv_cpu_id) {
+ printk(KERN_ERR "microcode: CPU%d cpu_id "
+ "not found in equivalent cpu table \n", cpu);
+ return 0;
+ }
+
+ if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) {
+ printk(KERN_ERR
+ "microcode: CPU%d patch does not match "
+ "(patch is %x, cpu extended is %x) \n",
+ cpu, mc_header->processor_rev_id[0],
+ (equiv_cpu_id & 0xff));
+ return 0;
+ }
+
+ if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) {
+ printk(KERN_ERR "microcode: CPU%d patch does not match "
+ "(patch is %x, cpu base id is %x) \n",
+ cpu, mc_header->processor_rev_id[1],
+ ((equiv_cpu_id >> 16) & 0xff));
+
+ return 0;
+ }
+
+ /* ucode may be northbridge specific */
+ if (mc_header->nb_dev_id) {
+ nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ (mc_header->nb_dev_id & 0xff),
+ NULL);
+ if ((!nb_pci_dev) ||
+ (mc_header->nb_rev_id != nb_pci_dev->revision)) {
+ printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu);
+ pci_dev_put(nb_pci_dev);
+ return 0;
+ }
+ pci_dev_put(nb_pci_dev);
+ }
+
+ /* ucode may be southbridge specific */
+ if (mc_header->sb_dev_id) {
+ sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ (mc_header->sb_dev_id & 0xff),
+ NULL);
+ if ((!sb_pci_dev) ||
+ (mc_header->sb_rev_id != sb_pci_dev->revision)) {
+ printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu);
+ pci_dev_put(sb_pci_dev);
+ return 0;
+ }
+ pci_dev_put(sb_pci_dev);
+ }
+
+ if (mc_header->patch_id <= rev)
+ return 0;
+
+ return 1;
+}
+
+static void apply_microcode_amd(int cpu)
+{
+ unsigned long flags;
+ unsigned int eax, edx;
+ unsigned int rev;
+ int cpu_num = raw_smp_processor_id();
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+ struct microcode_amd *mc_amd = uci->mc;
+ unsigned long addr;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu_num != cpu);
+
+ if (mc_amd == NULL)
+ return;
+
+ spin_lock_irqsave(&microcode_update_lock, flags);
+
+ addr = (unsigned long)&mc_amd->hdr.data_code;
+ edx = (unsigned int)(((unsigned long)upper_32_bits(addr)));
+ eax = (unsigned int)(((unsigned long)lower_32_bits(addr)));
+
+ asm volatile("movl %0, %%ecx; wrmsr" :
+ : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx");
+
+ /* get patch id after patching */
+ asm volatile("movl %1, %%ecx; rdmsr"
+ : "=a" (rev)
+ : "i" (0x0000008B) : "ecx");
+
+ spin_unlock_irqrestore(&microcode_update_lock, flags);
+
+ /* check current patch id and patch's id for match */
+ if (rev != mc_amd->hdr.patch_id) {
+ printk(KERN_ERR "microcode: CPU%d update from revision "
+ "0x%x to 0x%x failed\n", cpu_num,
+ mc_amd->hdr.patch_id, rev);
+ return;
+ }
+
+ printk(KERN_INFO "microcode: CPU%d updated from revision "
+ "0x%x to 0x%x \n",
+ cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
+
+ uci->cpu_sig.rev = rev;
+}
+
+static void * get_next_ucode(u8 *buf, unsigned int size,
+ int (*get_ucode_data)(void *, const void *, size_t),
+ unsigned int *mc_size)
+{
+ unsigned int total_size;
+#define UCODE_CONTAINER_SECTION_HDR 8
+ u8 section_hdr[UCODE_CONTAINER_SECTION_HDR];
+ void *mc;
+
+ if (get_ucode_data(section_hdr, buf, UCODE_CONTAINER_SECTION_HDR))
+ return NULL;
+
+ if (section_hdr[0] != UCODE_UCODE_TYPE) {
+ printk(KERN_ERR "microcode: error! "
+ "Wrong microcode payload type field\n");
+ return NULL;
+ }
+
+ total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
+
+ printk(KERN_INFO "microcode: size %u, total_size %u\n",
+ size, total_size);
+
+ if (total_size > size || total_size > UCODE_MAX_SIZE) {
+ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+ return NULL;
+ }
+
+ mc = vmalloc(UCODE_MAX_SIZE);
+ if (mc) {
+ memset(mc, 0, UCODE_MAX_SIZE);
+ if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size)) {
+ vfree(mc);
+ mc = NULL;
+ } else
+ *mc_size = total_size + UCODE_CONTAINER_SECTION_HDR;
+ }
+#undef UCODE_CONTAINER_SECTION_HDR
+ return mc;
+}
+
+
+static int install_equiv_cpu_table(u8 *buf,
+ int (*get_ucode_data)(void *, const void *, size_t))
+{
+#define UCODE_CONTAINER_HEADER_SIZE 12
+ u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE];
+ unsigned int *buf_pos = (unsigned int *)container_hdr;
+ unsigned long size;
+
+ if (get_ucode_data(&container_hdr, buf, UCODE_CONTAINER_HEADER_SIZE))
+ return 0;
+
+ size = buf_pos[2];
+
+ if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
+ printk(KERN_ERR "microcode: error! "
+ "Wrong microcode equivalnet cpu table\n");
+ return 0;
+ }
+
+ equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
+ if (!equiv_cpu_table) {
+ printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n");
+ return 0;
+ }
+
+ buf += UCODE_CONTAINER_HEADER_SIZE;
+ if (get_ucode_data(equiv_cpu_table, buf, size)) {
+ vfree(equiv_cpu_table);
+ return 0;
+ }
+
+ return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */
+#undef UCODE_CONTAINER_HEADER_SIZE
+}
+
+static void free_equiv_cpu_table(void)
+{
+ if (equiv_cpu_table) {
+ vfree(equiv_cpu_table);
+ equiv_cpu_table = NULL;
+ }
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+ int (*get_ucode_data)(void *, const void *, size_t))
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+ int new_rev = uci->cpu_sig.rev;
+ unsigned int leftover;
+ unsigned long offset;
+
+ offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data);
+ if (!offset) {
+ printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
+ return -EINVAL;
+ }
+
+ ucode_ptr += offset;
+ leftover = size - offset;
+
+ while (leftover) {
+ unsigned int uninitialized_var(mc_size);
+ struct microcode_header_amd *mc_header;
+
+ mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size);
+ if (!mc)
+ break;
+
+ mc_header = (struct microcode_header_amd *)mc;
+ if (get_matching_microcode(cpu, mc, new_rev)) {
+ if (new_mc)
+ vfree(new_mc);
+ new_rev = mc_header->patch_id;
+ new_mc = mc;
+ } else
+ vfree(mc);
+
+ ucode_ptr += mc_size;
+ leftover -= mc_size;
+ }
+
+ if (new_mc) {
+ if (!leftover) {
+ if (uci->mc)
+ vfree(uci->mc);
+ uci->mc = new_mc;
+ pr_debug("microcode: CPU%d found a matching microcode update with"
+ " version 0x%x (current=0x%x)\n",
+ cpu, new_rev, uci->cpu_sig.rev);
+ } else
+ vfree(new_mc);
+ }
+
+ free_equiv_cpu_table();
+
+ return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+ memcpy(to, from, n);
+ return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+ const char *fw_name = "amd-ucode/microcode_amd.bin";
+ const struct firmware *firmware;
+ int ret;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu != raw_smp_processor_id());
+
+ ret = request_firmware(&firmware, fw_name, device);
+ if (ret) {
+ printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name);
+ return ret;
+ }
+
+ ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+ &get_ucode_fw);
+
+ release_firmware(firmware);
+
+ return ret;
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+ printk(KERN_WARNING "microcode: AMD microcode update via /dev/cpu/microcode"
+ "is not supported\n");
+ return -1;
+}
+
+static void microcode_fini_cpu_amd(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ vfree(uci->mc);
+ uci->mc = NULL;
+}
+
+static struct microcode_ops microcode_amd_ops = {
+ .request_microcode_user = request_microcode_user,
+ .request_microcode_fw = request_microcode_fw,
+ .collect_cpu_info = collect_cpu_info_amd,
+ .apply_microcode = apply_microcode_amd,
+ .microcode_fini_cpu = microcode_fini_cpu_amd,
+};
+
+struct microcode_ops * __init init_amd_microcode(void)
+{
+ return &microcode_amd_ops;
+}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
new file mode 100644
index 00000000000..936d8d55f23
--- /dev/null
+++ b/arch/x86/kernel/microcode_core.c
@@ -0,0 +1,508 @@
+/*
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ * 2006 Shaohua Li <shaohua.li@intel.com>
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ * Software Developer's Manual
+ * Order Number 253668 or free download from:
+ *
+ * http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ * For more information, go to http://www.urbanmyth.org/microcode
+ *
+ * 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 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Initial release.
+ * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added read() support + cleanups.
+ * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added 'device trimming' support. open(O_WRONLY) zeroes
+ * and frees the saved copy of applied microcode.
+ * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Made to use devfs (/dev/cpu/microcode) + cleanups.
+ * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Added misc device support (now uses both devfs and misc).
+ * Added MICROCODE_IOCFREE ioctl to clear memory.
+ * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Messages for error cases (non Intel & no suitable microcode).
+ * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ * Removed ->release(). Removed exclusive open and status bitmap.
+ * Added microcode_rwsem to serialize read()/write()/ioctl().
+ * Removed global kernel lock usage.
+ * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ * Write 0 to 0x8B msr and then cpuid before reading revision,
+ * so that it works even if there were no update done by the
+ * BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ * to be 0 on my machine which is why it worked even when I
+ * disabled update by the BIOS)
+ * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>
+ * Intel Pentium 4 processor support and bugfixes.
+ * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ * Bugfix for HT (Hyper-Threading) enabled processors
+ * whereby processor resources are shared by all logical processors
+ * in a single CPU package.
+ * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>,
+ * Serialize updates as required on HT processors due to
+ * speculative nature of implementation.
+ * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ * Fix the panic when writing zero-length microcode chunk.
+ * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ * Jun Nakajima <jun.nakajima@intel.com>
+ * Support for the microcode updates in the new format.
+ * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ * because we no longer hold a copy of applied microcode
+ * in kernel memory.
+ * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ * Fix sigmatch() macro to handle old CPUs with pf == 0.
+ * Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+#define MICROCODE_VERSION "2.00"
+
+struct microcode_ops *microcode_ops;
+
+/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+static DEFINE_MUTEX(microcode_mutex);
+
+struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
+EXPORT_SYMBOL_GPL(ucode_cpu_info);
+
+#ifdef CONFIG_MICROCODE_OLD_INTERFACE
+static int do_microcode_update(const void __user *buf, size_t size)
+{
+ cpumask_t old;
+ int error = 0;
+ int cpu;
+
+ old = current->cpus_allowed;
+
+ for_each_online_cpu(cpu) {
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (!uci->valid)
+ continue;
+
+ set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+ error = microcode_ops->request_microcode_user(cpu, buf, size);
+ if (error < 0)
+ goto out;
+ if (!error)
+ microcode_ops->apply_microcode(cpu);
+ }
+out:
+ set_cpus_allowed_ptr(current, &old);
+ return error;
+}
+
+static int microcode_open(struct inode *unused1, struct file *unused2)
+{
+ cycle_kernel_lock();
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static ssize_t microcode_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ ssize_t ret;
+
+ if ((len >> PAGE_SHIFT) > num_physpages) {
+ printk(KERN_ERR "microcode: too much data (max %ld pages)\n",
+ num_physpages);
+ return -EINVAL;
+ }
+
+ get_online_cpus();
+ mutex_lock(&microcode_mutex);
+
+ ret = do_microcode_update(buf, len);
+ if (!ret)
+ ret = (ssize_t)len;
+
+ mutex_unlock(&microcode_mutex);
+ put_online_cpus();
+
+ return ret;
+}
+
+static const struct file_operations microcode_fops = {
+ .owner = THIS_MODULE,
+ .write = microcode_write,
+ .open = microcode_open,
+};
+
+static struct miscdevice microcode_dev = {
+ .minor = MICROCODE_MINOR,
+ .name = "microcode",
+ .fops = &microcode_fops,
+};
+
+static int __init microcode_dev_init(void)
+{
+ int error;
+
+ error = misc_register(&microcode_dev);
+ if (error) {
+ printk(KERN_ERR
+ "microcode: can't misc_register on minor=%d\n",
+ MICROCODE_MINOR);
+ return error;
+ }
+
+ return 0;
+}
+
+static void microcode_dev_exit(void)
+{
+ misc_deregister(&microcode_dev);
+}
+
+MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+#else
+#define microcode_dev_init() 0
+#define microcode_dev_exit() do { } while (0)
+#endif
+
+/* fake device for request_firmware */
+struct platform_device *microcode_pdev;
+
+static ssize_t reload_store(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf, size_t sz)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+ char *end;
+ unsigned long val = simple_strtoul(buf, &end, 0);
+ int err = 0;
+ int cpu = dev->id;
+
+ if (end == buf)
+ return -EINVAL;
+ if (val == 1) {
+ cpumask_t old = current->cpus_allowed;
+
+ get_online_cpus();
+ if (cpu_online(cpu)) {
+ set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+ mutex_lock(&microcode_mutex);
+ if (uci->valid) {
+ err = microcode_ops->request_microcode_fw(cpu,
+ &microcode_pdev->dev);
+ if (!err)
+ microcode_ops->apply_microcode(cpu);
+ }
+ mutex_unlock(&microcode_mutex);
+ set_cpus_allowed_ptr(current, &old);
+ }
+ put_online_cpus();
+ }
+ if (err)
+ return err;
+ return sz;
+}
+
+static ssize_t version_show(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+ return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
+}
+
+static ssize_t pf_show(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+ return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
+}
+
+static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
+static SYSDEV_ATTR(version, 0400, version_show, NULL);
+static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
+
+static struct attribute *mc_default_attrs[] = {
+ &attr_reload.attr,
+ &attr_version.attr,
+ &attr_processor_flags.attr,
+ NULL
+};
+
+static struct attribute_group mc_attr_group = {
+ .attrs = mc_default_attrs,
+ .name = "microcode",
+};
+
+static void microcode_fini_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ mutex_lock(&microcode_mutex);
+ microcode_ops->microcode_fini_cpu(cpu);
+ uci->valid = 0;
+ mutex_unlock(&microcode_mutex);
+}
+
+static void collect_cpu_info(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ memset(uci, 0, sizeof(*uci));
+ if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig))
+ uci->valid = 1;
+}
+
+static int microcode_resume_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct cpu_signature nsig;
+
+ pr_debug("microcode: CPU%d resumed\n", cpu);
+
+ if (!uci->mc)
+ return 1;
+
+ /*
+ * Let's verify that the 'cached' ucode does belong
+ * to this cpu (a bit of paranoia):
+ */
+ if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
+ microcode_fini_cpu(cpu);
+ return -1;
+ }
+
+ if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) {
+ microcode_fini_cpu(cpu);
+ /* Should we look for a new ucode here? */
+ return 1;
+ }
+
+ return 0;
+}
+
+void microcode_update_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ int err = 0;
+
+ /*
+ * Check if the system resume is in progress (uci->valid != NULL),
+ * otherwise just request a firmware:
+ */
+ if (uci->valid) {
+ err = microcode_resume_cpu(cpu);
+ } else {
+ collect_cpu_info(cpu);
+ if (uci->valid && system_state == SYSTEM_RUNNING)
+ err = microcode_ops->request_microcode_fw(cpu,
+ &microcode_pdev->dev);
+ }
+ if (!err)
+ microcode_ops->apply_microcode(cpu);
+}
+
+static void microcode_init_cpu(int cpu)
+{
+ cpumask_t old = current->cpus_allowed;
+
+ set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+ /* We should bind the task to the CPU */
+ BUG_ON(raw_smp_processor_id() != cpu);
+
+ mutex_lock(&microcode_mutex);
+ microcode_update_cpu(cpu);
+ mutex_unlock(&microcode_mutex);
+
+ set_cpus_allowed_ptr(current, &old);
+}
+
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+ int err, cpu = sys_dev->id;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ pr_debug("microcode: CPU%d added\n", cpu);
+ memset(uci, 0, sizeof(*uci));
+
+ err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
+ if (err)
+ return err;
+
+ microcode_init_cpu(cpu);
+ return 0;
+}
+
+static int mc_sysdev_remove(struct sys_device *sys_dev)
+{
+ int cpu = sys_dev->id;
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ pr_debug("microcode: CPU%d removed\n", cpu);
+ microcode_fini_cpu(cpu);
+ sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+ return 0;
+}
+
+static int mc_sysdev_resume(struct sys_device *dev)
+{
+ int cpu = dev->id;
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ /* only CPU 0 will apply ucode here */
+ microcode_update_cpu(0);
+ return 0;
+}
+
+static struct sysdev_driver mc_sysdev_driver = {
+ .add = mc_sysdev_add,
+ .remove = mc_sysdev_remove,
+ .resume = mc_sysdev_resume,
+};
+
+static __cpuinit int
+mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct sys_device *sys_dev;
+
+ sys_dev = get_cpu_sysdev(cpu);
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ microcode_init_cpu(cpu);
+ case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
+ pr_debug("microcode: CPU%d added\n", cpu);
+ if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
+ printk(KERN_ERR "microcode: Failed to create the sysfs "
+ "group for CPU%d\n", cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ /* Suspend is in progress, only remove the interface */
+ sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+ pr_debug("microcode: CPU%d removed\n", cpu);
+ break;
+ case CPU_DEAD:
+ case CPU_UP_CANCELED_FROZEN:
+ /* The CPU refused to come up during a system resume */
+ microcode_fini_cpu(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata mc_cpu_notifier = {
+ .notifier_call = mc_cpu_callback,
+};
+
+static int __init microcode_init(void)
+{
+ struct cpuinfo_x86 *c = &cpu_data(0);
+ int error;
+
+ if (c->x86_vendor == X86_VENDOR_INTEL)
+ microcode_ops = init_intel_microcode();
+ else if (c->x86_vendor == X86_VENDOR_AMD)
+ microcode_ops = init_amd_microcode();
+
+ if (!microcode_ops) {
+ printk(KERN_ERR "microcode: no support for this CPU vendor\n");
+ return -ENODEV;
+ }
+
+ error = microcode_dev_init();
+ if (error)
+ return error;
+ microcode_pdev = platform_device_register_simple("microcode", -1,
+ NULL, 0);
+ if (IS_ERR(microcode_pdev)) {
+ microcode_dev_exit();
+ return PTR_ERR(microcode_pdev);
+ }
+
+ get_online_cpus();
+ error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
+ put_online_cpus();
+ if (error) {
+ microcode_dev_exit();
+ platform_device_unregister(microcode_pdev);
+ return error;
+ }
+
+ register_hotcpu_notifier(&mc_cpu_notifier);
+
+ printk(KERN_INFO
+ "Microcode Update Driver: v" MICROCODE_VERSION
+ " <tigran@aivazian.fsnet.co.uk>"
+ " <peter.oruba@amd.com>\n");
+
+ return 0;
+}
+
+static void __exit microcode_exit(void)
+{
+ microcode_dev_exit();
+
+ unregister_hotcpu_notifier(&mc_cpu_notifier);
+
+ get_online_cpus();
+ sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
+ put_online_cpus();
+
+ platform_device_unregister(microcode_pdev);
+
+ microcode_ops = NULL;
+
+ printk(KERN_INFO
+ "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
+}
+
+module_init(microcode_init);
+module_exit(microcode_exit);
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
new file mode 100644
index 00000000000..622dc4a2178
--- /dev/null
+++ b/arch/x86/kernel/microcode_intel.c
@@ -0,0 +1,480 @@
+/*
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ * 2006 Shaohua Li <shaohua.li@intel.com>
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ * Software Developer's Manual
+ * Order Number 253668 or free download from:
+ *
+ * http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ * For more information, go to http://www.urbanmyth.org/microcode
+ *
+ * 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 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Initial release.
+ * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added read() support + cleanups.
+ * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Added 'device trimming' support. open(O_WRONLY) zeroes
+ * and frees the saved copy of applied microcode.
+ * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ * Made to use devfs (/dev/cpu/microcode) + cleanups.
+ * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Added misc device support (now uses both devfs and misc).
+ * Added MICROCODE_IOCFREE ioctl to clear memory.
+ * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ * Messages for error cases (non Intel & no suitable microcode).
+ * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ * Removed ->release(). Removed exclusive open and status bitmap.
+ * Added microcode_rwsem to serialize read()/write()/ioctl().
+ * Removed global kernel lock usage.
+ * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ * Write 0 to 0x8B msr and then cpuid before reading revision,
+ * so that it works even if there were no update done by the
+ * BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ * to be 0 on my machine which is why it worked even when I
+ * disabled update by the BIOS)
+ * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>
+ * Intel Pentium 4 processor support and bugfixes.
+ * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ * Bugfix for HT (Hyper-Threading) enabled processors
+ * whereby processor resources are shared by all logical processors
+ * in a single CPU package.
+ * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>,
+ * Serialize updates as required on HT processors due to
+ * speculative nature of implementation.
+ * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ * Fix the panic when writing zero-length microcode chunk.
+ * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ * Jun Nakajima <jun.nakajima@intel.com>
+ * Support for the microcode updates in the new format.
+ * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ * because we no longer hold a copy of applied microcode
+ * in kernel memory.
+ * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ * Fix sigmatch() macro to handle old CPUs with pf == 0.
+ * Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+struct microcode_header_intel {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int datasize;
+ unsigned int totalsize;
+ unsigned int reserved[3];
+};
+
+struct microcode_intel {
+ struct microcode_header_intel hdr;
+ unsigned int bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int cksum;
+};
+
+struct extended_sigtable {
+ unsigned int count;
+ unsigned int cksum;
+ unsigned int reserved[3];
+ struct extended_signature sigs[0];
+};
+
+#define DEFAULT_UCODE_DATASIZE (2000)
+#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
+#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
+#define DWSIZE (sizeof(u32))
+#define get_totalsize(mc) \
+ (((struct microcode_intel *)mc)->hdr.totalsize ? \
+ ((struct microcode_intel *)mc)->hdr.totalsize : \
+ DEFAULT_UCODE_TOTALSIZE)
+
+#define get_datasize(mc) \
+ (((struct microcode_intel *)mc)->hdr.datasize ? \
+ ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+
+#define sigmatch(s1, s2, p1, p2) \
+ (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+/* serialize access to the physical write to MSR 0x79 */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
+{
+ struct cpuinfo_x86 *c = &cpu_data(cpu_num);
+ unsigned int val[2];
+
+ memset(csig, 0, sizeof(*csig));
+
+ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+ cpu_has(c, X86_FEATURE_IA64)) {
+ printk(KERN_ERR "microcode: CPU%d not a capable Intel "
+ "processor\n", cpu_num);
+ return -1;
+ }
+
+ csig->sig = cpuid_eax(0x00000001);
+
+ if ((c->x86_model >= 5) || (c->x86 > 6)) {
+ /* get processor flags from MSR 0x17 */
+ rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+ csig->pf = 1 << ((val[1] >> 18) & 7);
+ }
+
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+ /* see notes above for revision 1.07. Apparent chip bug */
+ sync_core();
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev);
+ pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
+ csig->sig, csig->pf, csig->rev);
+
+ return 0;
+}
+
+static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
+{
+ return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
+}
+
+static inline int
+update_match_revision(struct microcode_header_intel *mc_header, int rev)
+{
+ return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+static int microcode_sanity_check(void *mc)
+{
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header = NULL;
+ struct extended_signature *ext_sig;
+ unsigned long total_size, data_size, ext_table_size;
+ int sum, orig_sum, ext_sigcount = 0, i;
+
+ total_size = get_totalsize(mc_header);
+ data_size = get_datasize(mc_header);
+ if (data_size + MC_HEADER_SIZE > total_size) {
+ printk(KERN_ERR "microcode: error! "
+ "Bad data size in microcode data file\n");
+ return -EINVAL;
+ }
+
+ if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+ printk(KERN_ERR "microcode: error! "
+ "Unknown microcode update format\n");
+ return -EINVAL;
+ }
+ ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+ if (ext_table_size) {
+ if ((ext_table_size < EXT_HEADER_SIZE)
+ || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+ printk(KERN_ERR "microcode: error! "
+ "Small exttable size in microcode data file\n");
+ return -EINVAL;
+ }
+ ext_header = mc + MC_HEADER_SIZE + data_size;
+ if (ext_table_size != exttable_size(ext_header)) {
+ printk(KERN_ERR "microcode: error! "
+ "Bad exttable size in microcode data file\n");
+ return -EFAULT;
+ }
+ ext_sigcount = ext_header->count;
+ }
+
+ /* check extended table checksum */
+ if (ext_table_size) {
+ int ext_table_sum = 0;
+ int *ext_tablep = (int *)ext_header;
+
+ i = ext_table_size / DWSIZE;
+ while (i--)
+ ext_table_sum += ext_tablep[i];
+ if (ext_table_sum) {
+ printk(KERN_WARNING "microcode: aborting, "
+ "bad extended signature table checksum\n");
+ return -EINVAL;
+ }
+ }
+
+ /* calculate the checksum */
+ orig_sum = 0;
+ i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+ while (i--)
+ orig_sum += ((int *)mc)[i];
+ if (orig_sum) {
+ printk(KERN_ERR "microcode: aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ if (!ext_table_size)
+ return 0;
+ /* check extended signature checksum */
+ for (i = 0; i < ext_sigcount; i++) {
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+ EXT_SIGNATURE_SIZE * i;
+ sum = orig_sum
+ - (mc_header->sig + mc_header->pf + mc_header->cksum)
+ + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+ if (sum) {
+ printk(KERN_ERR "microcode: aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+static int
+get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
+{
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header;
+ unsigned long total_size = get_totalsize(mc_header);
+ int ext_sigcount, i;
+ struct extended_signature *ext_sig;
+
+ if (!update_match_revision(mc_header, rev))
+ return 0;
+
+ if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
+ return 1;
+
+ /* Look for ext. headers: */
+ if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+ return 0;
+
+ ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+ ext_sigcount = ext_header->count;
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+ for (i = 0; i < ext_sigcount; i++) {
+ if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
+ return 1;
+ ext_sig++;
+ }
+ return 0;
+}
+
+static void apply_microcode(int cpu)
+{
+ unsigned long flags;
+ unsigned int val[2];
+ int cpu_num = raw_smp_processor_id();
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct microcode_intel *mc_intel = uci->mc;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu_num != cpu);
+
+ if (mc_intel == NULL)
+ return;
+
+ /* serialize access to the physical write to MSR 0x79 */
+ spin_lock_irqsave(&microcode_update_lock, flags);
+
+ /* write microcode via MSR 0x79 */
+ wrmsr(MSR_IA32_UCODE_WRITE,
+ (unsigned long) mc_intel->bits,
+ (unsigned long) mc_intel->bits >> 16 >> 16);
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+ /* see notes above for revision 1.07. Apparent chip bug */
+ sync_core();
+
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+ spin_unlock_irqrestore(&microcode_update_lock, flags);
+ if (val[1] != mc_intel->hdr.rev) {
+ printk(KERN_ERR "microcode: CPU%d update from revision "
+ "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]);
+ return;
+ }
+ printk(KERN_INFO "microcode: CPU%d updated from revision "
+ "0x%x to 0x%x, date = %04x-%02x-%02x \n",
+ cpu_num, uci->cpu_sig.rev, val[1],
+ mc_intel->hdr.date & 0xffff,
+ mc_intel->hdr.date >> 24,
+ (mc_intel->hdr.date >> 16) & 0xff);
+ uci->cpu_sig.rev = val[1];
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+ int (*get_ucode_data)(void *, const void *, size_t))
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+ int new_rev = uci->cpu_sig.rev;
+ unsigned int leftover = size;
+
+ while (leftover) {
+ struct microcode_header_intel mc_header;
+ unsigned int mc_size;
+
+ if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
+ break;
+
+ mc_size = get_totalsize(&mc_header);
+ if (!mc_size || mc_size > leftover) {
+ printk(KERN_ERR "microcode: error!"
+ "Bad data in microcode data file\n");
+ break;
+ }
+
+ mc = vmalloc(mc_size);
+ if (!mc)
+ break;
+
+ if (get_ucode_data(mc, ucode_ptr, mc_size) ||
+ microcode_sanity_check(mc) < 0) {
+ vfree(mc);
+ break;
+ }
+
+ if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
+ if (new_mc)
+ vfree(new_mc);
+ new_rev = mc_header.rev;
+ new_mc = mc;
+ } else
+ vfree(mc);
+
+ ucode_ptr += mc_size;
+ leftover -= mc_size;
+ }
+
+ if (new_mc) {
+ if (!leftover) {
+ if (uci->mc)
+ vfree(uci->mc);
+ uci->mc = (struct microcode_intel *)new_mc;
+ pr_debug("microcode: CPU%d found a matching microcode update with"
+ " version 0x%x (current=0x%x)\n",
+ cpu, new_rev, uci->cpu_sig.rev);
+ } else
+ vfree(new_mc);
+ }
+
+ return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+ memcpy(to, from, n);
+ return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+ char name[30];
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ const struct firmware *firmware;
+ int ret;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu != raw_smp_processor_id());
+ sprintf(name, "intel-ucode/%02x-%02x-%02x",
+ c->x86, c->x86_model, c->x86_mask);
+ ret = request_firmware(&firmware, name, device);
+ if (ret) {
+ pr_debug("microcode: data file %s load failed\n", name);
+ return ret;
+ }
+
+ ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+ &get_ucode_fw);
+
+ release_firmware(firmware);
+
+ return ret;
+}
+
+static int get_ucode_user(void *to, const void *from, size_t n)
+{
+ return copy_from_user(to, from, n);
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu != raw_smp_processor_id());
+
+ return generic_load_microcode(cpu, (void*)buf, size, &get_ucode_user);
+}
+
+static void microcode_fini_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ vfree(uci->mc);
+ uci->mc = NULL;
+}
+
+struct microcode_ops microcode_intel_ops = {
+ .request_microcode_user = request_microcode_user,
+ .request_microcode_fw = request_microcode_fw,
+ .collect_cpu_info = collect_cpu_info,
+ .apply_microcode = apply_microcode,
+ .microcode_fini_cpu = microcode_fini_cpu,
+};
+
+struct microcode_ops * __init init_intel_microcode(void)
+{
+ return &microcode_intel_ops;
+}
+
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
new file mode 100644
index 00000000000..0e9f1982b1d
--- /dev/null
+++ b/arch/x86/kernel/paravirt-spinlocks.c
@@ -0,0 +1,37 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/paravirt.h>
+
+static void default_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+ __raw_spin_lock(lock);
+}
+
+struct pv_lock_ops pv_lock_ops = {
+#ifdef CONFIG_SMP
+ .spin_is_locked = __ticket_spin_is_locked,
+ .spin_is_contended = __ticket_spin_is_contended,
+
+ .spin_lock = __ticket_spin_lock,
+ .spin_lock_flags = default_spin_lock_flags,
+ .spin_trylock = __ticket_spin_trylock,
+ .spin_unlock = __ticket_spin_unlock,
+#endif
+};
+EXPORT_SYMBOL(pv_lock_ops);
+
+void __init paravirt_use_bytelocks(void)
+{
+#ifdef CONFIG_SMP
+ pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
+ pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
+ pv_lock_ops.spin_lock = __byte_spin_lock;
+ pv_lock_ops.spin_trylock = __byte_spin_trylock;
+ pv_lock_ops.spin_unlock = __byte_spin_unlock;
+#endif
+}
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 6b0bb73998d..e4c8fb60887 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -268,17 +268,6 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
return __get_cpu_var(paravirt_lazy_mode);
}
-void __init paravirt_use_bytelocks(void)
-{
-#ifdef CONFIG_SMP
- pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
- pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
- pv_lock_ops.spin_lock = __byte_spin_lock;
- pv_lock_ops.spin_trylock = __byte_spin_trylock;
- pv_lock_ops.spin_unlock = __byte_spin_unlock;
-#endif
-}
-
struct pv_info pv_info = {
.name = "bare hardware",
.paravirt_enabled = 0,
@@ -349,6 +338,10 @@ struct pv_cpu_ops pv_cpu_ops = {
.write_ldt_entry = native_write_ldt_entry,
.write_gdt_entry = native_write_gdt_entry,
.write_idt_entry = native_write_idt_entry,
+
+ .alloc_ldt = paravirt_nop,
+ .free_ldt = paravirt_nop,
+
.load_sp0 = native_load_sp0,
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
@@ -460,18 +453,6 @@ struct pv_mmu_ops pv_mmu_ops = {
.set_fixmap = native_set_fixmap,
};
-struct pv_lock_ops pv_lock_ops = {
-#ifdef CONFIG_SMP
- .spin_is_locked = __ticket_spin_is_locked,
- .spin_is_contended = __ticket_spin_is_contended,
-
- .spin_lock = __ticket_spin_lock,
- .spin_trylock = __ticket_spin_trylock,
- .spin_unlock = __ticket_spin_unlock,
-#endif
-};
-EXPORT_SYMBOL(pv_lock_ops);
-
EXPORT_SYMBOL_GPL(pv_time_ops);
EXPORT_SYMBOL (pv_cpu_ops);
EXPORT_SYMBOL (pv_mmu_ops);
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 205188db962..0a1302fe6d4 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -76,47 +76,12 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
return ((unsigned long *)tsk->thread.sp)[3];
}
-#ifdef CONFIG_HOTPLUG_CPU
-#include <asm/nmi.h>
-
-static void cpu_exit_clear(void)
-{
- int cpu = raw_smp_processor_id();
-
- idle_task_exit();
-
- cpu_uninit();
- irq_ctx_exit(cpu);
-
- cpu_clear(cpu, cpu_callout_map);
- cpu_clear(cpu, cpu_callin_map);
-
- numa_remove_cpu(cpu);
- c1e_remove_cpu(cpu);
-}
-
-/* We don't actually take CPU down, just spin without interrupts. */
-static inline void play_dead(void)
-{
- /* This must be done before dead CPU ack */
- cpu_exit_clear();
- mb();
- /* Ack it */
- __get_cpu_var(cpu_state) = CPU_DEAD;
-
- /*
- * With physical CPU hotplug, we should halt the cpu
- */
- local_irq_disable();
- /* mask all interrupts, flush any and all caches, and halt */
- wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
static inline void play_dead(void)
{
BUG();
}
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
/*
* The idle thread. There's no useful work to be
@@ -158,7 +123,7 @@ void cpu_idle(void)
}
}
-void __show_registers(struct pt_regs *regs, int all)
+void __show_regs(struct pt_regs *regs, int all)
{
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
unsigned long d0, d1, d2, d3, d6, d7;
@@ -224,7 +189,7 @@ void __show_registers(struct pt_regs *regs, int all)
void show_regs(struct pt_regs *regs)
{
- __show_registers(regs, 1);
+ __show_regs(regs, 1);
show_trace(NULL, regs, &regs->sp, regs->bp);
}
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 2a8ccb9238b..cd8c0ed02b7 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -86,30 +86,12 @@ void exit_idle(void)
__exit_idle();
}
-#ifdef CONFIG_HOTPLUG_CPU
-DECLARE_PER_CPU(int, cpu_state);
-
-#include <linux/nmi.h>
-/* We halt the CPU with physical CPU hotplug */
-static inline void play_dead(void)
-{
- idle_task_exit();
- c1e_remove_cpu(raw_smp_processor_id());
-
- mb();
- /* Ack it */
- __get_cpu_var(cpu_state) = CPU_DEAD;
-
- local_irq_disable();
- /* mask all interrupts, flush any and all caches, and halt */
- wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
static inline void play_dead(void)
{
BUG();
}
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
/*
* The idle thread. There's no useful work to be
@@ -154,7 +136,7 @@ void cpu_idle(void)
}
/* Prints also some state that isn't saved in the pt_regs */
-void __show_regs(struct pt_regs *regs)
+void __show_regs(struct pt_regs *regs, int all)
{
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
unsigned long d0, d1, d2, d3, d6, d7;
@@ -193,6 +175,9 @@ void __show_regs(struct pt_regs *regs)
rdmsrl(MSR_GS_BASE, gs);
rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
+ if (!all)
+ return;
+
cr0 = read_cr0();
cr2 = read_cr2();
cr3 = read_cr3();
@@ -218,7 +203,7 @@ void __show_regs(struct pt_regs *regs)
void show_regs(struct pt_regs *regs)
{
printk(KERN_INFO "CPU %d:", smp_processor_id());
- __show_regs(regs);
+ __show_regs(regs, 1);
show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
}
@@ -754,12 +739,12 @@ unsigned long get_wchan(struct task_struct *p)
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
stack = (unsigned long)task_stack_page(p);
- if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE)
+ if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE)
return 0;
fp = *(u64 *)(p->thread.sp);
do {
if (fp < (unsigned long)stack ||
- fp > (unsigned long)stack+THREAD_SIZE)
+ fp >= (unsigned long)stack+THREAD_SIZE)
return 0;
ip = *(u64 *)(fp+8);
if (!in_sched_functions(ip))
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index e375b658efc..0a6d8c12e10 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -40,7 +40,9 @@ enum x86_regset {
REGSET_GENERAL,
REGSET_FP,
REGSET_XFP,
+ REGSET_IOPERM64 = REGSET_XFP,
REGSET_TLS,
+ REGSET_IOPERM32,
};
/*
@@ -555,6 +557,29 @@ static int ptrace_set_debugreg(struct task_struct *child,
return 0;
}
+/*
+ * These access the current or another (stopped) task's io permission
+ * bitmap for debugging or core dump.
+ */
+static int ioperm_active(struct task_struct *target,
+ const struct user_regset *regset)
+{
+ return target->thread.io_bitmap_max / regset->size;
+}
+
+static int ioperm_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ if (!target->thread.io_bitmap_ptr)
+ return -ENXIO;
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ target->thread.io_bitmap_ptr,
+ 0, IO_BITMAP_BYTES);
+}
+
#ifdef CONFIG_X86_PTRACE_BTS
/*
* The configuration for a particular BTS hardware implementation.
@@ -1385,6 +1410,12 @@ static const struct user_regset x86_64_regsets[] = {
.size = sizeof(long), .align = sizeof(long),
.active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
},
+ [REGSET_IOPERM64] = {
+ .core_note_type = NT_386_IOPERM,
+ .n = IO_BITMAP_LONGS,
+ .size = sizeof(long), .align = sizeof(long),
+ .active = ioperm_active, .get = ioperm_get
+ },
};
static const struct user_regset_view user_x86_64_view = {
@@ -1431,6 +1462,12 @@ static const struct user_regset x86_32_regsets[] = {
.active = regset_tls_active,
.get = regset_tls_get, .set = regset_tls_set
},
+ [REGSET_IOPERM32] = {
+ .core_note_type = NT_386_IOPERM,
+ .n = IO_BITMAP_BYTES / sizeof(u32),
+ .size = sizeof(u32), .align = sizeof(u32),
+ .active = ioperm_active, .get = ioperm_get
+ },
};
static const struct user_regset_view user_x86_32_view = {
@@ -1452,7 +1489,8 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
#endif
}
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+ int error_code, int si_code)
{
struct siginfo info;
@@ -1461,7 +1499,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
memset(&info, 0, sizeof(info));
info.si_signo = SIGTRAP;
- info.si_code = TRAP_BRKPT;
+ info.si_code = si_code;
/* User-mode ip? */
info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
@@ -1548,5 +1586,5 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
*/
if (test_thread_flag(TIF_SINGLESTEP) &&
tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
- send_sigtrap(current, regs, 0);
+ send_sigtrap(current, regs, 0, TRAP_BRKPT);
}
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index d1385881810..f6a11b9b1f9 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -354,9 +354,27 @@ static void ati_force_hpet_resume(void)
printk(KERN_DEBUG "Force enabled HPET at resume\n");
}
+static u32 ati_ixp4x0_rev(struct pci_dev *dev)
+{
+ u32 d;
+ u8 b;
+
+ pci_read_config_byte(dev, 0xac, &b);
+ b &= ~(1<<5);
+ pci_write_config_byte(dev, 0xac, b);
+ pci_read_config_dword(dev, 0x70, &d);
+ d |= 1<<8;
+ pci_write_config_dword(dev, 0x70, d);
+ pci_read_config_dword(dev, 0x8, &d);
+ d &= 0xff;
+ dev_printk(KERN_DEBUG, &dev->dev, "SB4X0 revision 0x%x\n", d);
+ return d;
+}
+
static void ati_force_enable_hpet(struct pci_dev *dev)
{
- u32 uninitialized_var(val);
+ u32 d, val;
+ u8 b;
if (hpet_address || force_hpet_address)
return;
@@ -366,14 +384,33 @@ static void ati_force_enable_hpet(struct pci_dev *dev)
return;
}
+ d = ati_ixp4x0_rev(dev);
+ if (d < 0x82)
+ return;
+
+ /* base address */
pci_write_config_dword(dev, 0x14, 0xfed00000);
pci_read_config_dword(dev, 0x14, &val);
+
+ /* enable interrupt */
+ outb(0x72, 0xcd6); b = inb(0xcd7);
+ b |= 0x1;
+ outb(0x72, 0xcd6); outb(b, 0xcd7);
+ outb(0x72, 0xcd6); b = inb(0xcd7);
+ if (!(b & 0x1))
+ return;
+ pci_read_config_dword(dev, 0x64, &d);
+ d |= (1<<10);
+ pci_write_config_dword(dev, 0x64, d);
+ pci_read_config_dword(dev, 0x64, &d);
+ if (!(d & (1<<10)))
+ return;
+
force_hpet_address = val;
force_hpet_resume_type = ATI_FORCE_HPET_RESUME;
dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
force_hpet_address);
cached_dev = dev;
- return;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
ati_force_enable_hpet);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 46c98efbbf8..2255782e8d4 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -302,7 +302,7 @@ static void __init relocate_initrd(void)
if (clen > MAX_MAP_CHUNK-slop)
clen = MAX_MAP_CHUNK-slop;
mapaddr = ramdisk_image & PAGE_MASK;
- p = early_ioremap(mapaddr, clen+slop);
+ p = early_memremap(mapaddr, clen+slop);
memcpy(q, p+slop, clen);
early_iounmap(p, clen+slop);
q += clen;
@@ -379,7 +379,7 @@ static void __init parse_setup_data(void)
return;
pa_data = boot_params.hdr.setup_data;
while (pa_data) {
- data = early_ioremap(pa_data, PAGE_SIZE);
+ data = early_memremap(pa_data, PAGE_SIZE);
switch (data->type) {
case SETUP_E820_EXT:
parse_e820_ext(data, pa_data);
@@ -402,7 +402,7 @@ static void __init e820_reserve_setup_data(void)
return;
pa_data = boot_params.hdr.setup_data;
while (pa_data) {
- data = early_ioremap(pa_data, sizeof(*data));
+ data = early_memremap(pa_data, sizeof(*data));
e820_update_range(pa_data, sizeof(*data)+data->len,
E820_RAM, E820_RESERVED_KERN);
found = 1;
@@ -428,7 +428,7 @@ static void __init reserve_early_setup_data(void)
return;
pa_data = boot_params.hdr.setup_data;
while (pa_data) {
- data = early_ioremap(pa_data, sizeof(*data));
+ data = early_memremap(pa_data, sizeof(*data));
sprintf(buf, "setup data %x", data->type);
reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
pa_data = data->next;
@@ -582,6 +582,190 @@ static struct x86_quirks default_x86_quirks __initdata;
struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
/*
+ * Some BIOSes seem to corrupt the low 64k of memory during events
+ * like suspend/resume and unplugging an HDMI cable. Reserve all
+ * remaining free memory in that area and fill it with a distinct
+ * pattern.
+ */
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+#define MAX_SCAN_AREAS 8
+
+static int __read_mostly memory_corruption_check = -1;
+
+static unsigned __read_mostly corruption_check_size = 64*1024;
+static unsigned __read_mostly corruption_check_period = 60; /* seconds */
+
+static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static int num_scan_areas;
+
+
+static int set_corruption_check(char *arg)
+{
+ char *end;
+
+ memory_corruption_check = simple_strtol(arg, &end, 10);
+
+ return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check", set_corruption_check);
+
+static int set_corruption_check_period(char *arg)
+{
+ char *end;
+
+ corruption_check_period = simple_strtoul(arg, &end, 10);
+
+ return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_period", set_corruption_check_period);
+
+static int set_corruption_check_size(char *arg)
+{
+ char *end;
+ unsigned size;
+
+ size = memparse(arg, &end);
+
+ if (*end == '\0')
+ corruption_check_size = size;
+
+ return (size == corruption_check_size) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_size", set_corruption_check_size);
+
+
+static void __init setup_bios_corruption_check(void)
+{
+ u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */
+
+ if (memory_corruption_check == -1) {
+ memory_corruption_check =
+#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+ 1
+#else
+ 0
+#endif
+ ;
+ }
+
+ if (corruption_check_size == 0)
+ memory_corruption_check = 0;
+
+ if (!memory_corruption_check)
+ return;
+
+ corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
+
+ while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
+ u64 size;
+ addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+
+ if (addr == 0)
+ break;
+
+ if ((addr + size) > corruption_check_size)
+ size = corruption_check_size - addr;
+
+ if (size == 0)
+ break;
+
+ e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+ scan_areas[num_scan_areas].addr = addr;
+ scan_areas[num_scan_areas].size = size;
+ num_scan_areas++;
+
+ /* Assume we've already mapped this early memory */
+ memset(__va(addr), 0, size);
+
+ addr += size;
+ }
+
+ printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
+ num_scan_areas);
+ update_e820();
+}
+
+static struct timer_list periodic_check_timer;
+
+void check_for_bios_corruption(void)
+{
+ int i;
+ int corruption = 0;
+
+ if (!memory_corruption_check)
+ return;
+
+ for(i = 0; i < num_scan_areas; i++) {
+ unsigned long *addr = __va(scan_areas[i].addr);
+ unsigned long size = scan_areas[i].size;
+
+ for(; size; addr++, size -= sizeof(unsigned long)) {
+ if (!*addr)
+ continue;
+ printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
+ addr, __pa(addr), *addr);
+ corruption = 1;
+ *addr = 0;
+ }
+ }
+
+ WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
+}
+
+static void periodic_check_for_corruption(unsigned long data)
+{
+ check_for_bios_corruption();
+ mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
+}
+
+void start_periodic_check_for_corruption(void)
+{
+ if (!memory_corruption_check || corruption_check_period == 0)
+ return;
+
+ printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
+ corruption_check_period);
+
+ init_timer(&periodic_check_timer);
+ periodic_check_timer.function = &periodic_check_for_corruption;
+ periodic_check_for_corruption(0);
+}
+#endif
+
+static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
+{
+ printk(KERN_NOTICE
+ "%s detected: BIOS may corrupt low RAM, working it around.\n",
+ d->ident);
+
+ e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
+ sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+
+ return 0;
+}
+
+/* List of systems that have known low memory corruption BIOS problems */
+static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
+#ifdef CONFIG_X86_RESERVE_LOW_64K
+ {
+ .callback = dmi_low_memory_corruption,
+ .ident = "AMI BIOS",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ },
+ },
+ {
+ .callback = dmi_low_memory_corruption,
+ .ident = "Phoenix BIOS",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+ },
+ },
+#endif
+ {}
+};
+
+/*
* Determine if we were loaded by an EFI loader. If so, then we have also been
* passed the efi memmap, systab, etc., so we should use these data structures
* for initialization. Note, the efi init code path is determined by the
@@ -715,6 +899,10 @@ void __init setup_arch(char **cmdline_p)
finish_e820_parsing();
+ dmi_scan_machine();
+
+ dmi_check_system(bad_bios_dmi_table);
+
#ifdef CONFIG_X86_32
probe_roms();
#endif
@@ -771,6 +959,10 @@ void __init setup_arch(char **cmdline_p)
high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
#endif
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+ setup_bios_corruption_check();
+#endif
+
/* max_pfn_mapped is updated here */
max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
max_pfn_mapped = max_low_pfn_mapped;
@@ -799,8 +991,6 @@ void __init setup_arch(char **cmdline_p)
vsmp_init();
#endif
- dmi_scan_machine();
-
io_delay_init();
/*
@@ -808,6 +998,8 @@ void __init setup_arch(char **cmdline_p)
*/
acpi_boot_table_init();
+ early_acpi_boot_init();
+
#ifdef CONFIG_ACPI_NUMA
/*
* Parse SRAT to discover nodes.
@@ -903,3 +1095,5 @@ void __init setup_arch(char **cmdline_p)
#endif
#endif
}
+
+
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index b21070ea33a..d6dd057d0f2 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -27,6 +27,7 @@
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/vdso.h>
+#include <asm/syscall.h>
#include <asm/syscalls.h>
#include "sigframe.h"
@@ -112,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx)
return do_sigaltstack(uss, uoss, regs->sp);
}
+#define COPY(x) { \
+ err |= __get_user(regs->x, &sc->x); \
+}
+
+#define COPY_SEG(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->seg = tmp; \
+}
+
+#define COPY_SEG_STRICT(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->seg = tmp | 3; \
+}
+
+#define GET_SEG(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ loadsegment(seg, tmp); \
+}
/*
* Do a signal return; undo the signal stack.
@@ -120,28 +142,13 @@ static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
unsigned long *pax)
{
+ void __user *buf;
+ unsigned int tmpflags;
unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
-#define COPY(x) err |= __get_user(regs->x, &sc->x)
-
-#define COPY_SEG(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- regs->seg = tmp; }
-
-#define COPY_SEG_STRICT(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- regs->seg = tmp|3; }
-
-#define GET_SEG(seg) \
- { unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
- loadsegment(seg, tmp); }
-
GET_SEG(gs);
COPY_SEG(fs);
COPY_SEG(es);
@@ -151,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
COPY_SEG_STRICT(cs);
COPY_SEG_STRICT(ss);
- {
- unsigned int tmpflags;
-
- err |= __get_user(tmpflags, &sc->flags);
- regs->flags = (regs->flags & ~FIX_EFLAGS) |
- (tmpflags & FIX_EFLAGS);
- regs->orig_ax = -1; /* disable syscall checks */
- }
-
- {
- void __user *buf;
+ err |= __get_user(tmpflags, &sc->flags);
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+ regs->orig_ax = -1; /* disable syscall checks */
- err |= __get_user(buf, &sc->fpstate);
- err |= restore_i387_xstate(buf);
- }
+ err |= __get_user(buf, &sc->fpstate);
+ err |= restore_i387_xstate(buf);
err |= __get_user(*pax, &sc->ax);
return err;
@@ -214,9 +212,8 @@ badframe:
return 0;
}
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+static long do_rt_sigreturn(struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *)&__unused;
struct rt_sigframe __user *frame;
unsigned long ax;
sigset_t set;
@@ -242,10 +239,17 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused)
return ax;
badframe:
- force_sig(SIGSEGV, current);
+ signal_fault(regs, frame, "rt_sigreturn");
return 0;
}
+asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+{
+ struct pt_regs *regs = (struct pt_regs *)&__unused;
+
+ return do_rt_sigreturn(regs);
+}
+
/*
* Set up a signal frame.
*/
@@ -337,39 +341,29 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
}
static int
-setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
- struct pt_regs *regs)
+__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+ struct pt_regs *regs)
{
struct sigframe __user *frame;
void __user *restorer;
int err = 0;
- int usig;
void __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
- usig = current_thread_info()->exec_domain
- && current_thread_info()->exec_domain->signal_invmap
- && sig < 32
- ? current_thread_info()->exec_domain->signal_invmap[sig]
- : sig;
+ if (__put_user(sig, &frame->sig))
+ return -EFAULT;
- err = __put_user(usig, &frame->sig);
- if (err)
- goto give_sigsegv;
-
- err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
- if (err)
- goto give_sigsegv;
+ if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+ return -EFAULT;
if (_NSIG_WORDS > 1) {
- err = __copy_to_user(&frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- if (err)
- goto give_sigsegv;
+ if (__copy_to_user(&frame->extramask, &set->sig[1],
+ sizeof(frame->extramask)))
+ return -EFAULT;
}
if (current->mm->context.vdso)
@@ -394,7 +388,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
@@ -409,38 +403,27 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
regs->cs = __USER_CS;
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
void __user *restorer;
int err = 0;
- int usig;
void __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
-
- usig = current_thread_info()->exec_domain
- && current_thread_info()->exec_domain->signal_invmap
- && sig < 32
- ? current_thread_info()->exec_domain->signal_invmap[sig]
- : sig;
+ return -EFAULT;
- err |= __put_user(usig, &frame->sig);
+ err |= __put_user(sig, &frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
err |= copy_siginfo_to_user(&frame->info, info);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Create the ucontext. */
if (cpu_has_xsave)
@@ -456,7 +439,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up to return from userspace. */
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -476,12 +459,12 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
regs->ip = (unsigned long)ka->sa.sa_handler;
- regs->ax = (unsigned long)usig;
+ regs->ax = (unsigned long)sig;
regs->dx = (unsigned long)&frame->info;
regs->cx = (unsigned long)&frame->uc;
@@ -491,15 +474,48 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->cs = __USER_CS;
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
/*
* OK, we're invoking a handler:
*/
+static int signr_convert(int sig)
+{
+ struct thread_info *info = current_thread_info();
+
+ if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
+ return info->exec_domain->signal_invmap[sig];
+ return sig;
+}
+
+#define is_ia32 1
+#define ia32_setup_frame __setup_frame
+#define ia32_setup_rt_frame __setup_rt_frame
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ int usig = signr_convert(sig);
+ int ret;
+
+ /* Set up the stack frame */
+ if (is_ia32) {
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+ else
+ ret = ia32_setup_frame(usig, ka, set, regs);
+ } else
+ ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+ if (ret) {
+ force_sigsegv(sig, current);
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs *regs)
@@ -507,9 +523,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
int ret;
/* Are we from a system call? */
- if ((long)regs->orig_ax >= 0) {
+ if (syscall_get_nr(current, regs) >= 0) {
/* If so, check system call restarting.. */
- switch (regs->ax) {
+ switch (syscall_get_error(current, regs)) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->ax = -EINTR;
@@ -536,15 +552,20 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
regs->flags &= ~X86_EFLAGS_TF;
- /* Set up the stack frame */
- if (ka->sa.sa_flags & SA_SIGINFO)
- ret = setup_rt_frame(sig, ka, info, oldset, regs);
- else
- ret = setup_frame(sig, ka, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
if (ret)
return ret;
+#ifdef CONFIG_X86_64
+ /*
+ * This has nothing to do with segment registers,
+ * despite the name. This magic affects uaccess.h
+ * macros' behavior. Reset it to the normal setting.
+ */
+ set_fs(USER_DS);
+#endif
+
/*
* Clear the direction flag as per the ABI for function entry.
*/
@@ -571,6 +592,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
return 0;
}
+#define NR_restart_syscall __NR_restart_syscall
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -623,9 +645,9 @@ static void do_signal(struct pt_regs *regs)
}
/* Did we come from a system call? */
- if ((long)regs->orig_ax >= 0) {
+ if (syscall_get_nr(current, regs) >= 0) {
/* Restart the system call - no handlers present */
- switch (regs->ax) {
+ switch (syscall_get_error(current, regs)) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
@@ -634,7 +656,7 @@ static void do_signal(struct pt_regs *regs)
break;
case -ERESTART_RESTARTBLOCK:
- regs->ax = __NR_restart_syscall;
+ regs->ax = NR_restart_syscall;
regs->ip -= 2;
break;
}
@@ -657,6 +679,12 @@ static void do_signal(struct pt_regs *regs)
void
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+ /* notify userspace of pending MCEs */
+ if (thread_info_flags & _TIF_MCE_NOTIFY)
+ mce_notify_user();
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
+
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
@@ -666,5 +694,23 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
tracehook_notify_resume(regs);
}
+#ifdef CONFIG_X86_32
clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
+}
+
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+{
+ struct task_struct *me = current;
+
+ if (show_unhandled_signals && printk_ratelimit()) {
+ printk(KERN_INFO
+ "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+ me->comm, me->pid, where, frame,
+ regs->ip, regs->sp, regs->orig_ax);
+ print_vma_addr(" in ", regs->ip);
+ printk(KERN_CONT "\n");
+ }
+
+ force_sig(SIGSEGV, me);
}
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index 823a55bf8c3..a5c9627f4db 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
return do_sigaltstack(uss, uoss, regs->sp);
}
+#define COPY(x) { \
+ err |= __get_user(regs->x, &sc->x); \
+}
+
+#define COPY_SEG_STRICT(seg) { \
+ unsigned short tmp; \
+ err |= __get_user(tmp, &sc->seg); \
+ regs->seg = tmp | 3; \
+}
+
/*
* Do a signal return; undo the signal stack.
*/
@@ -59,13 +69,13 @@ static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
unsigned long *pax)
{
+ void __user *buf;
+ unsigned int tmpflags;
unsigned int err = 0;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
-#define COPY(x) (err |= __get_user(regs->x, &sc->x))
-
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip);
COPY(r8);
@@ -80,34 +90,24 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
/* 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 */
- }
+ COPY_SEG_STRICT(cs);
- {
- unsigned int tmpflags;
- err |= __get_user(tmpflags, &sc->flags);
- regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
- regs->orig_ax = -1; /* disable syscall checks */
- }
+ err |= __get_user(tmpflags, &sc->flags);
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+ regs->orig_ax = -1; /* disable syscall checks */
- {
- struct _fpstate __user *buf;
- err |= __get_user(buf, &sc->fpstate);
- err |= restore_i387_xstate(buf);
- }
+ err |= __get_user(buf, &sc->fpstate);
+ err |= restore_i387_xstate(buf);
err |= __get_user(*pax, &sc->ax);
return err;
}
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+static long do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
- sigset_t set;
unsigned long ax;
+ sigset_t set;
frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -130,10 +130,15 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
return ax;
badframe:
- signal_fault(regs, frame, "sigreturn");
+ signal_fault(regs, frame, "rt_sigreturn");
return 0;
}
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+ return do_rt_sigreturn(regs);
+}
+
/*
* Set up a signal frame.
*/
@@ -195,8 +200,8 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
return (void __user *)round_down(sp - size, 64);
}
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
void __user *fp = NULL;
@@ -209,17 +214,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
if (save_i387_xstate(fp) < 0)
- err |= -1;
+ return -EFAULT;
} else
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
if (ka->sa.sa_flags & SA_SIGINFO) {
- err |= copy_siginfo_to_user(&frame->info, info);
- if (err)
- goto give_sigsegv;
+ if (copy_siginfo_to_user(&frame->info, info))
+ return -EFAULT;
}
/* Create the ucontext. */
@@ -247,11 +251,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else {
/* could use a vstub here */
- goto give_sigsegv;
+ return -EFAULT;
}
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up registers for signal handler */
regs->di = sig;
@@ -271,15 +275,45 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->cs = __USER_CS;
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
/*
* OK, we're invoking a handler
*/
+static int signr_convert(int sig)
+{
+ return sig;
+}
+
+#ifdef CONFIG_IA32_EMULATION
+#define is_ia32 test_thread_flag(TIF_IA32)
+#else
+#define is_ia32 0
+#endif
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ int usig = signr_convert(sig);
+ int ret;
+
+ /* Set up the stack frame */
+ if (is_ia32) {
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+ else
+ ret = ia32_setup_frame(usig, ka, set, regs);
+ } else
+ ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+ if (ret) {
+ force_sigsegv(sig, current);
+ return -EFAULT;
+ }
+
+ return ret;
+}
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
@@ -317,51 +351,48 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
regs->flags &= ~X86_EFLAGS_TF;
-#ifdef CONFIG_IA32_EMULATION
- if (test_thread_flag(TIF_IA32)) {
- if (ka->sa.sa_flags & SA_SIGINFO)
- ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs);
- else
- ret = ia32_setup_frame(sig, ka, oldset, regs);
- } else
-#endif
ret = setup_rt_frame(sig, ka, info, oldset, regs);
- if (ret == 0) {
- /*
- * This has nothing to do with segment registers,
- * despite the name. This magic affects uaccess.h
- * macros' behavior. Reset it to the normal setting.
- */
- set_fs(USER_DS);
+ if (ret)
+ return ret;
- /*
- * Clear the direction flag as per the ABI for function entry.
- */
- regs->flags &= ~X86_EFLAGS_DF;
+#ifdef CONFIG_X86_64
+ /*
+ * This has nothing to do with segment registers,
+ * despite the name. This magic affects uaccess.h
+ * macros' behavior. Reset it to the normal setting.
+ */
+ set_fs(USER_DS);
+#endif
- /*
- * Clear TF when entering the signal handler, but
- * notify any tracer that was single-stepping it.
- * The tracer may want to single-step inside the
- * handler too.
- */
- regs->flags &= ~X86_EFLAGS_TF;
+ /*
+ * Clear the direction flag as per the ABI for function entry.
+ */
+ regs->flags &= ~X86_EFLAGS_DF;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ /*
+ * Clear TF when entering the signal handler, but
+ * notify any tracer that was single-stepping it.
+ * The tracer may want to single-step inside the
+ * handler too.
+ */
+ regs->flags &= ~X86_EFLAGS_TF;
- tracehook_signal_handler(sig, info, ka, regs,
- test_thread_flag(TIF_SINGLESTEP));
- }
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked, sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
- return ret;
+ tracehook_signal_handler(sig, info, ka, regs,
+ test_thread_flag(TIF_SINGLESTEP));
+
+ return 0;
}
+#define NR_restart_syscall \
+ test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -391,7 +422,8 @@ static void do_signal(struct pt_regs *regs)
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
- /* Re-enable any watchpoints before delivering the
+ /*
+ * Re-enable any watchpoints before delivering the
* signal to user space. The processor register will
* have been cleared if the watchpoint triggered
* inside the kernel.
@@ -399,7 +431,7 @@ static void do_signal(struct pt_regs *regs)
if (current->thread.debugreg7)
set_debugreg(current->thread.debugreg7, 7);
- /* Whee! Actually deliver the signal. */
+ /* Whee! Actually deliver the signal. */
if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
/*
* A signal was successfully delivered; the saved
@@ -422,10 +454,9 @@ static void do_signal(struct pt_regs *regs)
regs->ax = regs->orig_ax;
regs->ip -= 2;
break;
+
case -ERESTART_RESTARTBLOCK:
- regs->ax = test_thread_flag(TIF_IA32) ?
- __NR_ia32_restart_syscall :
- __NR_restart_syscall;
+ regs->ax = NR_restart_syscall;
regs->ip -= 2;
break;
}
@@ -441,14 +472,18 @@ static void do_signal(struct pt_regs *regs)
}
}
-void do_notify_resume(struct pt_regs *regs, void *unused,
- __u32 thread_info_flags)
+/*
+ * notification of userspace execution resumption
+ * - triggered by the TIF_WORK_MASK flags
+ */
+void
+do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{
-#ifdef CONFIG_X86_MCE
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
/* notify userspace of pending MCEs */
if (thread_info_flags & _TIF_MCE_NOTIFY)
mce_notify_user();
-#endif /* CONFIG_X86_MCE */
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
@@ -458,17 +493,23 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
+
+#ifdef CONFIG_X86_32
+ clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
}
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
{
struct task_struct *me = current;
+
if (show_unhandled_signals && printk_ratelimit()) {
- printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
- me->comm, me->pid, where, frame, regs->ip,
- regs->sp, regs->orig_ax);
+ printk(KERN_INFO
+ "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+ me->comm, me->pid, where, frame,
+ regs->ip, regs->sp, regs->orig_ax);
print_vma_addr(" in ", regs->ip);
- printk("\n");
+ printk(KERN_CONT "\n");
}
force_sig(SIGSEGV, me);
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 361b7a4c640..18f9b19f5f8 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -214,12 +214,16 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
struct smp_ops smp_ops = {
.smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
.smp_prepare_cpus = native_smp_prepare_cpus,
- .cpu_up = native_cpu_up,
.smp_cpus_done = native_smp_cpus_done,
.smp_send_stop = native_smp_send_stop,
.smp_send_reschedule = native_smp_send_reschedule,
+ .cpu_up = native_cpu_up,
+ .cpu_die = native_cpu_die,
+ .cpu_disable = native_cpu_disable,
+ .play_dead = native_play_dead,
+
.send_call_func_ipi = native_send_call_func_ipi,
.send_call_func_single_ipi = native_send_call_func_single_ipi,
};
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 9056f7e272c..8c3aca7cb34 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -52,6 +52,7 @@
#include <asm/desc.h>
#include <asm/nmi.h>
#include <asm/irq.h>
+#include <asm/idle.h>
#include <asm/smp.h>
#include <asm/trampoline.h>
#include <asm/cpu.h>
@@ -333,14 +334,17 @@ static void __cpuinit start_secondary(void *unused)
* does not change while we are assigning vectors to cpus. Holding
* this lock ensures we don't half assign or remove an irq from a cpu.
*/
- ipi_call_lock_irq();
+ ipi_call_lock();
lock_vector_lock();
__setup_vector_irq(smp_processor_id());
cpu_set(smp_processor_id(), cpu_online_map);
unlock_vector_lock();
- ipi_call_unlock_irq();
+ ipi_call_unlock();
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+ /* enable local interrupts */
+ local_irq_enable();
+
setup_secondary_clock();
wmb();
@@ -595,10 +599,12 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
* Give the other CPU some time to accept the IPI.
*/
udelay(200);
- maxlvt = lapic_get_maxlvt();
- if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
- apic_write(APIC_ESR, 0);
- accept_status = (apic_read(APIC_ESR) & 0xEF);
+ if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+ maxlvt = lapic_get_maxlvt();
+ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
+ apic_write(APIC_ESR, 0);
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ }
pr_debug("NMI sent.\n");
if (send_status)
@@ -1255,39 +1261,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
check_nmi_watchdog();
}
-#ifdef CONFIG_HOTPLUG_CPU
-
-static void remove_siblinginfo(int cpu)
-{
- int sibling;
- struct cpuinfo_x86 *c = &cpu_data(cpu);
-
- for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) {
- cpu_clear(cpu, per_cpu(cpu_core_map, sibling));
- /*/
- * last thread sibling in this cpu core going down
- */
- if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1)
- cpu_data(sibling).booted_cores--;
- }
-
- for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu))
- cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling));
- cpus_clear(per_cpu(cpu_sibling_map, cpu));
- cpus_clear(per_cpu(cpu_core_map, cpu));
- c->phys_proc_id = 0;
- c->cpu_core_id = 0;
- cpu_clear(cpu, cpu_sibling_setup_map);
-}
-
-static int additional_cpus __initdata = -1;
-
-static __init int setup_additional_cpus(char *s)
-{
- return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL;
-}
-early_param("additional_cpus", setup_additional_cpus);
-
/*
* cpu_possible_map should be static, it cannot change as cpu's
* are onlined, or offlined. The reason is per-cpu data-structures
@@ -1307,21 +1280,13 @@ early_param("additional_cpus", setup_additional_cpus);
*/
__init void prefill_possible_map(void)
{
- int i;
- int possible;
+ int i, possible;
/* no processor from mptable or madt */
if (!num_processors)
num_processors = 1;
- if (additional_cpus == -1) {
- if (disabled_cpus > 0)
- additional_cpus = disabled_cpus;
- else
- additional_cpus = 0;
- }
-
- possible = num_processors + additional_cpus;
+ possible = num_processors + disabled_cpus;
if (possible > NR_CPUS)
possible = NR_CPUS;
@@ -1334,6 +1299,31 @@ __init void prefill_possible_map(void)
nr_cpu_ids = possible;
}
+#ifdef CONFIG_HOTPLUG_CPU
+
+static void remove_siblinginfo(int cpu)
+{
+ int sibling;
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+ for_each_cpu_mask_nr(sibling, per_cpu(cpu_core_map, cpu)) {
+ cpu_clear(cpu, per_cpu(cpu_core_map, sibling));
+ /*/
+ * last thread sibling in this cpu core going down
+ */
+ if (cpus_weight(per_cpu(cpu_sibling_map, cpu)) == 1)
+ cpu_data(sibling).booted_cores--;
+ }
+
+ for_each_cpu_mask_nr(sibling, per_cpu(cpu_sibling_map, cpu))
+ cpu_clear(cpu, per_cpu(cpu_sibling_map, sibling));
+ cpus_clear(per_cpu(cpu_sibling_map, cpu));
+ cpus_clear(per_cpu(cpu_core_map, cpu));
+ c->phys_proc_id = 0;
+ c->cpu_core_id = 0;
+ cpu_clear(cpu, cpu_sibling_setup_map);
+}
+
static void __ref remove_cpu_from_maps(int cpu)
{
cpu_clear(cpu, cpu_online_map);
@@ -1344,25 +1334,9 @@ static void __ref remove_cpu_from_maps(int cpu)
numa_remove_cpu(cpu);
}
-int __cpu_disable(void)
+void cpu_disable_common(void)
{
int cpu = smp_processor_id();
-
- /*
- * Perhaps use cpufreq to drop frequency, but that could go
- * into generic code.
- *
- * We won't take down the boot processor on i386 due to some
- * interrupts only being able to be serviced by the BSP.
- * Especially so if we're not using an IOAPIC -zwane
- */
- if (cpu == 0)
- return -EBUSY;
-
- if (nmi_watchdog == NMI_LOCAL_APIC)
- stop_apic_nmi_watchdog(NULL);
- clear_local_APIC();
-
/*
* HACK:
* Allow any queued timer interrupts to get serviced
@@ -1380,10 +1354,32 @@ int __cpu_disable(void)
remove_cpu_from_maps(cpu);
unlock_vector_lock();
fixup_irqs(cpu_online_map);
+}
+
+int native_cpu_disable(void)
+{
+ int cpu = smp_processor_id();
+
+ /*
+ * Perhaps use cpufreq to drop frequency, but that could go
+ * into generic code.
+ *
+ * We won't take down the boot processor on i386 due to some
+ * interrupts only being able to be serviced by the BSP.
+ * Especially so if we're not using an IOAPIC -zwane
+ */
+ if (cpu == 0)
+ return -EBUSY;
+
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ stop_apic_nmi_watchdog(NULL);
+ clear_local_APIC();
+
+ cpu_disable_common();
return 0;
}
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
{
/* We don't do anything here: idle task is faking death itself. */
unsigned int i;
@@ -1400,15 +1396,45 @@ void __cpu_die(unsigned int cpu)
}
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
}
+
+void play_dead_common(void)
+{
+ idle_task_exit();
+ reset_lazy_tlbstate();
+ irq_ctx_exit(raw_smp_processor_id());
+ c1e_remove_cpu(raw_smp_processor_id());
+
+ mb();
+ /* Ack it */
+ __get_cpu_var(cpu_state) = CPU_DEAD;
+
+ /*
+ * With physical CPU hotplug, we should halt the cpu
+ */
+ local_irq_disable();
+}
+
+void native_play_dead(void)
+{
+ play_dead_common();
+ wbinvd_halt();
+}
+
#else /* ... !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
+int native_cpu_disable(void)
{
return -ENOSYS;
}
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
{
/* We said "no" in __cpu_disable */
BUG();
}
+
+void native_play_dead(void)
+{
+ BUG();
+}
+
#endif
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c
index bbecf8b6bf9..77b400f06ea 100644
--- a/arch/x86/kernel/time_32.c
+++ b/arch/x86/kernel/time_32.c
@@ -47,10 +47,9 @@ unsigned long profile_pc(struct pt_regs *regs)
unsigned long pc = instruction_pointer(regs);
#ifdef CONFIG_SMP
- if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs) &&
- in_lock_functions(pc)) {
+ if (!user_mode_vm(regs) && in_lock_functions(pc)) {
#ifdef CONFIG_FRAME_POINTER
- return *(unsigned long *)(regs->bp + 4);
+ return *(unsigned long *)(regs->bp + sizeof(long));
#else
unsigned long *sp = (unsigned long *)&regs->sp;
@@ -95,6 +94,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
do_timer_interrupt_hook();
+#ifdef CONFIG_MCA
if (MCA_bus) {
/* The PS/2 uses level-triggered interrupts. You can't
turn them off, nor would you want to (any attempt to
@@ -108,6 +108,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
u8 irq_v = inb_p( 0x61 ); /* read the current state */
outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */
}
+#endif
return IRQ_HANDLED;
}
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c
index e3d49c553af..cb19d650c21 100644
--- a/arch/x86/kernel/time_64.c
+++ b/arch/x86/kernel/time_64.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/time.h>
+#include <linux/mca.h>
#include <asm/i8253.h>
#include <asm/hpet.h>
@@ -33,23 +34,34 @@ unsigned long profile_pc(struct pt_regs *regs)
/* Assume the lock function has either no stack frame or a copy
of flags from PUSHF
Eflags always has bits 22 and up cleared unlike kernel addresses. */
- if (!user_mode(regs) && in_lock_functions(pc)) {
+ if (!user_mode_vm(regs) && in_lock_functions(pc)) {
+#ifdef CONFIG_FRAME_POINTER
+ return *(unsigned long *)(regs->bp + sizeof(long));
+#else
unsigned long *sp = (unsigned long *)regs->sp;
if (sp[0] >> 22)
return sp[0];
if (sp[1] >> 22)
return sp[1];
+#endif
}
return pc;
}
EXPORT_SYMBOL(profile_pc);
-static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
{
add_pda(irq0_irqs, 1);
global_clock_event->event_handler(global_clock_event);
+#ifdef CONFIG_MCA
+ if (MCA_bus) {
+ u8 irq_v = inb_p(0x61); /* read the current state */
+ outb_p(irq_v|0x80, 0x61); /* reset the IRQ */
+ }
+#endif
+
return IRQ_HANDLED;
}
@@ -100,7 +112,7 @@ unsigned long __init calibrate_cpu(void)
}
static struct irqaction irq0 = {
- .handler = timer_event_interrupt,
+ .handler = timer_interrupt,
.flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
.mask = CPU_MASK_NONE,
.name = "timer"
@@ -111,16 +123,13 @@ void __init hpet_time_init(void)
if (!hpet_enable())
setup_pit_timer();
+ irq0.mask = cpumask_of_cpu(0);
setup_irq(0, &irq0);
}
void __init time_init(void)
{
tsc_init();
- if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
- vgetcpu_mode = VGETCPU_RDTSCP;
- else
- vgetcpu_mode = VGETCPU_LSL;
late_time_init = choose_time_init();
}
diff --git a/arch/x86/kernel/tlb_32.c b/arch/x86/kernel/tlb_32.c
index fec1ecedc9b..e00534b3353 100644
--- a/arch/x86/kernel/tlb_32.c
+++ b/arch/x86/kernel/tlb_32.c
@@ -241,3 +241,11 @@ void flush_tlb_all(void)
on_each_cpu(do_flush_tlb_all, NULL, 1);
}
+void reset_lazy_tlbstate(void)
+{
+ int cpu = raw_smp_processor_id();
+
+ per_cpu(cpu_tlbstate, cpu).state = 0;
+ per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps.c
index da5a5964fcc..e062974cce3 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps.c
@@ -7,13 +7,11 @@
*/
/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'.
+ * Handle hardware traps and faults.
*/
#include <linux/interrupt.h>
#include <linux/kallsyms.h>
#include <linux/spinlock.h>
-#include <linux/highmem.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/utsname.h>
@@ -32,6 +30,8 @@
#include <linux/bug.h>
#include <linux/nmi.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/io.h>
#ifdef CONFIG_EISA
#include <linux/ioport.h>
@@ -46,21 +46,31 @@
#include <linux/edac.h>
#endif
-#include <asm/arch_hooks.h>
#include <asm/stacktrace.h>
#include <asm/processor.h>
#include <asm/debugreg.h>
#include <asm/atomic.h>
#include <asm/system.h>
#include <asm/unwind.h>
+#include <asm/traps.h>
#include <asm/desc.h>
#include <asm/i387.h>
+
+#include <mach_traps.h>
+
+#ifdef CONFIG_X86_64
+#include <asm/pgalloc.h>
+#include <asm/proto.h>
+#include <asm/pda.h>
+#else
+#include <asm/processor-flags.h>
+#include <asm/arch_hooks.h>
#include <asm/nmi.h>
#include <asm/smp.h>
#include <asm/io.h>
#include <asm/traps.h>
-#include "mach_traps.h"
+#include "cpu/mcheck/mce.h"
DECLARE_BITMAP(used_vectors, NR_VECTORS);
EXPORT_SYMBOL_GPL(used_vectors);
@@ -77,418 +87,104 @@ char ignore_fpu_irq;
*/
gate_desc idt_table[256]
__attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 24;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-void printk_address(unsigned long address, int reliable)
-{
-#ifdef CONFIG_KALLSYMS
- unsigned long offset = 0;
- unsigned long symsize;
- const char *symname;
- char *modname;
- char *delim = ":";
- char namebuf[KSYM_NAME_LEN];
- char reliab[4] = "";
-
- symname = kallsyms_lookup(address, &symsize, &offset,
- &modname, namebuf);
- if (!symname) {
- printk(" [<%08lx>]\n", address);
- return;
- }
- if (!reliable)
- strcpy(reliab, "? ");
-
- if (!modname)
- modname = delim = "";
- printk(" [<%08lx>] %s%s%s%s%s+0x%lx/0x%lx\n",
- address, reliab, delim, modname, delim, symname, offset, symsize);
-#else
- printk(" [<%08lx>]\n", address);
#endif
-}
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
- void *p, unsigned int size)
-{
- void *t = tinfo;
- return p > t && p <= t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
- struct stack_frame *next_frame;
- unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
- unsigned long *stack, unsigned long bp,
- const struct stacktrace_ops *ops, void *data)
-{
- struct stack_frame *frame = (struct stack_frame *)bp;
-
- while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) {
- unsigned long addr;
-
- addr = *stack;
- if (__kernel_text_address(addr)) {
- if ((unsigned long) stack == bp + 4) {
- ops->address(data, addr, 1);
- frame = frame->next_frame;
- bp = (unsigned long) frame;
- } else {
- ops->address(data, addr, bp == 0);
- }
- }
- stack++;
- }
- return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, unsigned long bp,
- const struct stacktrace_ops *ops, void *data)
-{
- if (!task)
- task = current;
-
- if (!stack) {
- unsigned long dummy;
- stack = &dummy;
- if (task != current)
- stack = (unsigned long *)task->thread.sp;
- }
-
-#ifdef CONFIG_FRAME_POINTER
- if (!bp) {
- if (task == current) {
- /* Grab bp right from our regs */
- asm("movl %%ebp, %0" : "=r" (bp) :);
- } else {
- /* bp is the last reg pushed by switch_to */
- bp = *(unsigned long *) task->thread.sp;
- }
- }
-#endif
-
- for (;;) {
- struct thread_info *context;
-
- context = (struct thread_info *)
- ((unsigned long)stack & (~(THREAD_SIZE - 1)));
- bp = print_context_stack(context, stack, bp, ops, data);
- /*
- * Should be after the line below, but somewhere
- * in early boot context comes out corrupted and we
- * can't reference it:
- */
- if (ops->stack(data, "IRQ") < 0)
- break;
- stack = (unsigned long *)context->previous_esp;
- if (!stack)
- break;
- touch_nmi_watchdog();
- }
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
- printk(data);
- print_symbol(msg, symbol);
- printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
- printk("%s%s\n", (char *)data, msg);
-}
-static int print_trace_stack(void *data, char *name)
-{
- return 0;
-}
-
-/*
- * Print one address/symbol entries per line.
- */
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
- printk("%s [<%08lx>] ", (char *)data, addr);
- if (!reliable)
- printk("? ");
- print_symbol("%s\n", addr);
- touch_nmi_watchdog();
-}
-
-static const struct stacktrace_ops print_trace_ops = {
- .warning = print_trace_warning,
- .warning_symbol = print_trace_warning_symbol,
- .stack = print_trace_stack,
- .address = print_trace_address,
-};
+static int ignore_nmis;
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, unsigned long bp, char *log_lvl)
+static inline void conditional_sti(struct pt_regs *regs)
{
- dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
- printk("%s =======================\n", log_lvl);
+ if (regs->flags & X86_EFLAGS_IF)
+ local_irq_enable();
}
-void show_trace(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, unsigned long bp)
+static inline void preempt_conditional_sti(struct pt_regs *regs)
{
- show_trace_log_lvl(task, regs, stack, bp, "");
+ inc_preempt_count();
+ if (regs->flags & X86_EFLAGS_IF)
+ local_irq_enable();
}
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, unsigned long bp, char *log_lvl)
+static inline void preempt_conditional_cli(struct pt_regs *regs)
{
- unsigned long *stack;
- int i;
-
- if (sp == NULL) {
- if (task)
- sp = (unsigned long *)task->thread.sp;
- else
- sp = (unsigned long *)&sp;
- }
-
- stack = sp;
- for (i = 0; i < kstack_depth_to_print; i++) {
- if (kstack_end(stack))
- break;
- if (i && ((i % 8) == 0))
- printk("\n%s ", log_lvl);
- printk("%08lx ", *stack++);
- }
- printk("\n%sCall Trace:\n", log_lvl);
-
- show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+ if (regs->flags & X86_EFLAGS_IF)
+ local_irq_disable();
+ dec_preempt_count();
}
-void show_stack(struct task_struct *task, unsigned long *sp)
+#ifdef CONFIG_X86_32
+static inline void
+die_if_kernel(const char *str, struct pt_regs *regs, long err)
{
- printk(" ");
- show_stack_log_lvl(task, NULL, sp, 0, "");
+ if (!user_mode_vm(regs))
+ die(str, regs, err);
}
/*
- * The architecture-independent dump_stack generator
+ * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
+ * invalid offset set (the LAZY one) and the faulting thread has
+ * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS,
+ * we set the offset field correctly and return 1.
*/
-void dump_stack(void)
+static int lazy_iobitmap_copy(void)
{
- unsigned long bp = 0;
- unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
- if (!bp)
- asm("movl %%ebp, %0" : "=r" (bp):);
-#endif
-
- printk("Pid: %d, comm: %.20s %s %s %.*s\n",
- current->pid, current->comm, print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
-
- show_trace(current, NULL, &stack, bp);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
- int i;
+ struct thread_struct *thread;
+ struct tss_struct *tss;
+ int cpu;
- print_modules();
- __show_registers(regs, 0);
+ cpu = get_cpu();
+ tss = &per_cpu(init_tss, cpu);
+ thread = &current->thread;
- printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
- TASK_COMM_LEN, current->comm, task_pid_nr(current),
- current_thread_info(), current, task_thread_info(current));
- /*
- * When in-kernel, we also print out the stack and code at the
- * time of the fault..
- */
- if (!user_mode_vm(regs)) {
- unsigned int code_prologue = code_bytes * 43 / 64;
- unsigned int code_len = code_bytes;
- unsigned char c;
- u8 *ip;
-
- printk("\n" KERN_EMERG "Stack: ");
- show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
-
- printk(KERN_EMERG "Code: ");
-
- ip = (u8 *)regs->ip - code_prologue;
- if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
- /* try starting at EIP */
- ip = (u8 *)regs->ip;
- code_len = code_len - code_prologue + 1;
- }
- for (i = 0; i < code_len; i++, ip++) {
- if (ip < (u8 *)PAGE_OFFSET ||
- probe_kernel_address(ip, c)) {
- printk(" Bad EIP value.");
- break;
- }
- if (ip == (u8 *)regs->ip)
- printk("<%02x> ", c);
- else
- printk("%02x ", c);
+ if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+ thread->io_bitmap_ptr) {
+ memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
+ thread->io_bitmap_max);
+ /*
+ * If the previously set map was extending to higher ports
+ * than the current one, pad extra space with 0xff (no access).
+ */
+ if (thread->io_bitmap_max < tss->io_bitmap_max) {
+ memset((char *) tss->io_bitmap +
+ thread->io_bitmap_max, 0xff,
+ tss->io_bitmap_max - thread->io_bitmap_max);
}
- }
- printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
- unsigned short ud2;
-
- if (ip < PAGE_OFFSET)
- return 0;
- if (probe_kernel_address((unsigned short *)ip, ud2))
- return 0;
-
- return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
- unsigned long flags;
-
- oops_enter();
-
- if (die_owner != raw_smp_processor_id()) {
- console_verbose();
- raw_local_irq_save(flags);
- __raw_spin_lock(&die_lock);
- die_owner = smp_processor_id();
- die_nest_count = 0;
- bust_spinlocks(1);
- } else {
- raw_local_irq_save(flags);
- }
- die_nest_count++;
- return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
- bust_spinlocks(0);
- die_owner = -1;
- add_taint(TAINT_DIE);
- __raw_spin_unlock(&die_lock);
- raw_local_irq_restore(flags);
-
- if (!regs)
- return;
-
- if (kexec_should_crash(current))
- crash_kexec(regs);
-
- if (in_interrupt())
- panic("Fatal exception in interrupt");
-
- if (panic_on_oops)
- panic("Fatal exception");
-
- oops_exit();
- do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
- unsigned short ss;
- unsigned long sp;
+ tss->io_bitmap_max = thread->io_bitmap_max;
+ tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
+ tss->io_bitmap_owner = thread;
+ put_cpu();
- printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
- printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
- printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
- printk("DEBUG_PAGEALLOC");
-#endif
- printk("\n");
- if (notify_die(DIE_OOPS, str, regs, err,
- current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
return 1;
-
- show_registers(regs);
- /* Executive summary in case the oops scrolled away */
- sp = (unsigned long) (&regs->sp);
- savesegment(ss, ss);
- if (user_mode(regs)) {
- sp = regs->sp;
- ss = regs->ss & 0xffff;
}
- printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
- print_symbol("%s", regs->ip);
- printk(" SS:ESP %04x:%08lx\n", ss, sp);
- return 0;
-}
-
-/*
- * This is gone through when something in the kernel has done something bad
- * and is about to be terminated:
- */
-void die(const char *str, struct pt_regs *regs, long err)
-{
- unsigned long flags = oops_begin();
-
- if (die_nest_count < 3) {
- report_bug(regs->ip, regs);
-
- if (__die(str, regs, err))
- regs = NULL;
- } else {
- printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
- }
-
- oops_end(flags, regs, SIGSEGV);
-}
+ put_cpu();
-static inline void
-die_if_kernel(const char *str, struct pt_regs *regs, long err)
-{
- if (!user_mode_vm(regs))
- die(str, regs, err);
+ return 0;
}
+#endif
static void __kprobes
-do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs *regs,
+do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
long error_code, siginfo_t *info)
{
struct task_struct *tsk = current;
+#ifdef CONFIG_X86_32
if (regs->flags & X86_VM_MASK) {
- if (vm86)
+ /*
+ * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
+ * On nmi (interrupt 2), do_trap should not be called.
+ */
+ if (trapnr < 6)
goto vm86_trap;
goto trap_signal;
}
+#endif
if (!user_mode(regs))
goto kernel_trap;
+#ifdef CONFIG_X86_32
trap_signal:
+#endif
/*
* We want error_code and trap_no set for userspace faults and
* kernelspace faults which result in die(), but not
@@ -501,6 +197,18 @@ trap_signal:
tsk->thread.error_code = error_code;
tsk->thread.trap_no = trapnr;
+#ifdef CONFIG_X86_64
+ if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+ printk_ratelimit()) {
+ printk(KERN_INFO
+ "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+ tsk->comm, tsk->pid, str,
+ regs->ip, regs->sp, error_code);
+ print_vma_addr(" in ", regs->ip);
+ printk("\n");
+ }
+#endif
+
if (info)
force_sig_info(signr, info, tsk);
else
@@ -515,29 +223,29 @@ kernel_trap:
}
return;
+#ifdef CONFIG_X86_32
vm86_trap:
if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
error_code, trapnr))
goto trap_signal;
return;
+#endif
}
#define DO_ERROR(trapnr, signr, str, name) \
-void do_##name(struct pt_regs *regs, long error_code) \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
{ \
- trace_hardirqs_fixup(); \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
- do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
+ conditional_sti(regs); \
+ do_trap(trapnr, signr, str, regs, error_code, NULL); \
}
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \
-void do_##name(struct pt_regs *regs, long error_code) \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
{ \
siginfo_t info; \
- if (irq) \
- local_irq_enable(); \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
@@ -545,90 +253,68 @@ void do_##name(struct pt_regs *regs, long error_code) \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
- do_trap(trapnr, signr, str, 0, regs, error_code, &info); \
+ conditional_sti(regs); \
+ do_trap(trapnr, signr, str, regs, error_code, &info); \
}
-#define DO_VM86_ERROR(trapnr, signr, str, name) \
-void do_##name(struct pt_regs *regs, long error_code) \
-{ \
- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- == NOTIFY_STOP) \
- return; \
- do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
-}
-
-#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
-void do_##name(struct pt_regs *regs, long error_code) \
-{ \
- siginfo_t info; \
- info.si_signo = signr; \
- info.si_errno = 0; \
- info.si_code = sicode; \
- info.si_addr = (void __user *)siaddr; \
- trace_hardirqs_fixup(); \
- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- == NOTIFY_STOP) \
- return; \
- do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
-}
-
-DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-#ifndef CONFIG_KPROBES
-DO_VM86_ERROR(3, SIGTRAP, "int3", int3)
-#endif
-DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
+DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
+DO_ERROR(4, SIGSEGV, "overflow", overflow)
+DO_ERROR(5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+#ifdef CONFIG_X86_32
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
-DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1)
+#endif
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
+
+#ifdef CONFIG_X86_64
+/* Runs on IST stack */
+dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
+{
+ if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
+ 12, SIGBUS) == NOTIFY_STOP)
+ return;
+ preempt_conditional_sti(regs);
+ do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
+ preempt_conditional_cli(regs);
+}
+
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
+{
+ static const char str[] = "double fault";
+ struct task_struct *tsk = current;
+
+ /* Return not checked because double check cannot be ignored */
+ notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
-void __kprobes
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = 8;
+
+ /* This is always a kernel trap and never fixable (and thus must
+ never return). */
+ for (;;)
+ die(str, regs, error_code);
+}
+#endif
+
+dotraplinkage void __kprobes
do_general_protection(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk;
- struct thread_struct *thread;
- struct tss_struct *tss;
- int cpu;
- cpu = get_cpu();
- tss = &per_cpu(init_tss, cpu);
- thread = &current->thread;
-
- /*
- * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
- * invalid offset set (the LAZY one) and the faulting thread has
- * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS
- * and we set the offset field correctly. Then we let the CPU to
- * restart the faulting instruction.
- */
- if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
- thread->io_bitmap_ptr) {
- memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
- thread->io_bitmap_max);
- /*
- * If the previously set map was extending to higher ports
- * than the current one, pad extra space with 0xff (no access).
- */
- if (thread->io_bitmap_max < tss->io_bitmap_max) {
- memset((char *) tss->io_bitmap +
- thread->io_bitmap_max, 0xff,
- tss->io_bitmap_max - thread->io_bitmap_max);
- }
- tss->io_bitmap_max = thread->io_bitmap_max;
- tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
- tss->io_bitmap_owner = thread;
- put_cpu();
+ conditional_sti(regs);
+#ifdef CONFIG_X86_32
+ if (lazy_iobitmap_copy()) {
+ /* restart the faulting instruction */
return;
}
- put_cpu();
if (regs->flags & X86_VM_MASK)
goto gp_in_vm86;
+#endif
tsk = current;
if (!user_mode(regs))
@@ -650,10 +336,12 @@ do_general_protection(struct pt_regs *regs, long error_code)
force_sig(SIGSEGV, tsk);
return;
+#ifdef CONFIG_X86_32
gp_in_vm86:
local_irq_enable();
handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
return;
+#endif
gp_in_kernel:
if (fixup_exception(regs))
@@ -690,7 +378,8 @@ mem_parity_error(unsigned char reason, struct pt_regs *regs)
printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
/* Clear and disable the memory parity error line. */
- clear_mem_error(reason);
+ reason = (reason & 0xf) | 4;
+ outb(reason, 0x61);
}
static notrace __kprobes void
@@ -716,7 +405,8 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
static notrace __kprobes void
unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
{
- if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+ if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
+ NOTIFY_STOP)
return;
#ifdef CONFIG_MCA
/*
@@ -739,41 +429,6 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
}
-static DEFINE_SPINLOCK(nmi_print_lock);
-
-void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
- if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
- return;
-
- spin_lock(&nmi_print_lock);
- /*
- * We are in trouble anyway, lets at least try
- * to get a message out:
- */
- bust_spinlocks(1);
- printk(KERN_EMERG "%s", str);
- printk(" on CPU%d, ip %08lx, registers:\n",
- smp_processor_id(), regs->ip);
- show_registers(regs);
- if (do_panic)
- panic("Non maskable interrupt");
- console_silent();
- spin_unlock(&nmi_print_lock);
- bust_spinlocks(0);
-
- /*
- * If we are in kernel we are probably nested up pretty bad
- * and might aswell get out now while we still can:
- */
- if (!user_mode_vm(regs)) {
- current->thread.trap_no = 2;
- crash_kexec(regs);
- }
-
- do_exit(SIGSEGV);
-}
-
static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
{
unsigned char reason = 0;
@@ -812,22 +467,25 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
mem_parity_error(reason, regs);
if (reason & 0x40)
io_check_error(reason, regs);
+#ifdef CONFIG_X86_32
/*
* Reassert NMI in case it became active meanwhile
* as it's edge-triggered:
*/
reassert_nmi();
+#endif
}
-notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code)
+dotraplinkage notrace __kprobes void
+do_nmi(struct pt_regs *regs, long error_code)
{
- int cpu;
-
nmi_enter();
- cpu = smp_processor_id();
-
- ++nmi_count(cpu);
+#ifdef CONFIG_X86_32
+ { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
+#else
+ add_pda(__nmi_count, 1);
+#endif
if (!ignore_nmis)
default_do_nmi(regs);
@@ -847,21 +505,44 @@ void restart_nmi(void)
acpi_nmi_enable();
}
-#ifdef CONFIG_KPROBES
-void __kprobes do_int3(struct pt_regs *regs, long error_code)
+/* May run on IST stack. */
+dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
{
- trace_hardirqs_fixup();
-
+#ifdef CONFIG_KPROBES
if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
== NOTIFY_STOP)
return;
- /*
- * This is an interrupt gate, because kprobes wants interrupts
- * disabled. Normal trap handlers don't.
- */
- restore_interrupts(regs);
+#else
+ if (notify_die(DIE_TRAP, "int3", regs, error_code, 3, SIGTRAP)
+ == NOTIFY_STOP)
+ return;
+#endif
+
+ preempt_conditional_sti(regs);
+ do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
+ preempt_conditional_cli(regs);
+}
- do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
+#ifdef CONFIG_X86_64
+/* Help handler running on IST stack to switch back to user stack
+ for scheduling or signal handling. The actual stack switch is done in
+ entry.S */
+asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
+{
+ struct pt_regs *regs = eregs;
+ /* Did already sync */
+ if (eregs == (struct pt_regs *)eregs->sp)
+ ;
+ /* Exception from user space */
+ else if (user_mode(eregs))
+ regs = task_pt_regs(current);
+ /* Exception from kernel and interrupts are enabled. Move to
+ kernel process stack. */
+ else if (eregs->flags & X86_EFLAGS_IF)
+ regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
+ if (eregs != regs)
+ *regs = *eregs;
+ return regs;
}
#endif
@@ -886,13 +567,14 @@ void __kprobes do_int3(struct pt_regs *regs, long error_code)
* about restoring all the debug state, and ptrace doesn't have to
* find every occurrence of the TF bit that could be saved away even
* by user code)
+ *
+ * May run on IST stack.
*/
-void __kprobes do_debug(struct pt_regs *regs, long error_code)
+dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk = current;
- unsigned int condition;
-
- trace_hardirqs_fixup();
+ unsigned long condition;
+ int si_code;
get_debugreg(condition, 6);
@@ -905,9 +587,9 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
SIGTRAP) == NOTIFY_STOP)
return;
+
/* It's safe to allow irq's after DR6 has been saved */
- if (regs->flags & X86_EFLAGS_IF)
- local_irq_enable();
+ preempt_conditional_sti(regs);
/* Mask out spurious debug traps due to lazy DR7 setting */
if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
@@ -915,8 +597,10 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
goto clear_dr7;
}
+#ifdef CONFIG_X86_32
if (regs->flags & X86_VM_MASK)
goto debug_vm86;
+#endif
/* Save debug status register where ptrace can see it */
tsk->thread.debugreg6 = condition;
@@ -926,17 +610,13 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
* kernel space (but re-enable TF when returning to user mode).
*/
if (condition & DR_STEP) {
- /*
- * We already checked v86 mode above, so we can
- * check for kernel mode by just checking the CPL
- * of CS.
- */
if (!user_mode(regs))
goto clear_TF_reenable;
}
+ si_code = get_si_code(condition);
/* Ok, finally something we can handle */
- send_sigtrap(tsk, regs, error_code);
+ send_sigtrap(tsk, regs, error_code, si_code);
/*
* Disable additional traps. They'll be re-enabled when
@@ -944,18 +624,37 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
*/
clear_dr7:
set_debugreg(0, 7);
+ preempt_conditional_cli(regs);
return;
+#ifdef CONFIG_X86_32
debug_vm86:
handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+ preempt_conditional_cli(regs);
return;
+#endif
clear_TF_reenable:
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
regs->flags &= ~X86_EFLAGS_TF;
+ preempt_conditional_cli(regs);
return;
}
+#ifdef CONFIG_X86_64
+static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
+{
+ if (fixup_exception(regs))
+ return 1;
+
+ notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
+ /* Illegal floating point operation in the kernel */
+ current->thread.trap_no = trapnr;
+ die(str, regs, 0);
+ return 0;
+}
+#endif
+
/*
* Note that we play around with the 'TS' bit in an attempt to get
* the correct behaviour even in the presence of the asynchronous
@@ -992,7 +691,9 @@ void math_error(void __user *ip)
swd = get_fpu_swd(task);
switch (swd & ~cwd & 0x3f) {
case 0x000: /* No unmasked exception */
+#ifdef CONFIG_X86_32
return;
+#endif
default: /* Multiple exceptions */
break;
case 0x001: /* Invalid Op */
@@ -1020,9 +721,18 @@ void math_error(void __user *ip)
force_sig_info(SIGFPE, &info, task);
}
-void do_coprocessor_error(struct pt_regs *regs, long error_code)
+dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
{
+ conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
ignore_fpu_irq = 1;
+#else
+ if (!user_mode(regs) &&
+ kernel_math_error(regs, "kernel x87 math error", 16))
+ return;
+#endif
+
math_error((void __user *)regs->ip);
}
@@ -1074,8 +784,12 @@ static void simd_math_error(void __user *ip)
force_sig_info(SIGFPE, &info, task);
}
-void do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
+dotraplinkage void
+do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
{
+ conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
if (cpu_has_xmm) {
/* Handle SIMD FPU exceptions on PIII+ processors. */
ignore_fpu_irq = 1;
@@ -1094,16 +808,25 @@ void do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
current->thread.error_code = error_code;
die_if_kernel("cache flush denied", regs, error_code);
force_sig(SIGSEGV, current);
+#else
+ if (!user_mode(regs) &&
+ kernel_math_error(regs, "kernel simd math error", 19))
+ return;
+ simd_math_error((void __user *)regs->ip);
+#endif
}
-void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
+dotraplinkage void
+do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
{
+ conditional_sti(regs);
#if 0
/* No need to warn about this any longer. */
printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
#endif
}
+#ifdef CONFIG_X86_32
unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
{
struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
@@ -1122,6 +845,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
return new_kesp;
}
+#else
+asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
+{
+}
+
+asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+{
+}
+#endif
/*
* 'math_state_restore()' saves the current math information in the
@@ -1154,14 +886,24 @@ asmlinkage void math_state_restore(void)
}
clts(); /* Allow maths ops (or we recurse) */
+#ifdef CONFIG_X86_32
restore_fpu(tsk);
+#else
+ /*
+ * Paranoid restore. send a SIGSEGV if we fail to restore the state.
+ */
+ if (unlikely(restore_fpu_checking(tsk))) {
+ stts();
+ force_sig(SIGSEGV, tsk);
+ return;
+ }
+#endif
thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */
tsk->fpu_counter++;
}
EXPORT_SYMBOL_GPL(math_state_restore);
#ifndef CONFIG_MATH_EMULATION
-
asmlinkage void math_emulate(long arg)
{
printk(KERN_EMERG
@@ -1170,12 +912,54 @@ asmlinkage void math_emulate(long arg)
force_sig(SIGFPE, current);
schedule();
}
-
#endif /* CONFIG_MATH_EMULATION */
+dotraplinkage void __kprobes
+do_device_not_available(struct pt_regs *regs, long error)
+{
+#ifdef CONFIG_X86_32
+ if (read_cr0() & X86_CR0_EM) {
+ conditional_sti(regs);
+ math_emulate(0);
+ } else {
+ math_state_restore(); /* interrupts still off */
+ conditional_sti(regs);
+ }
+#else
+ math_state_restore();
+#endif
+}
+
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_MCE
+dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error)
+{
+ conditional_sti(regs);
+ machine_check_vector(regs, error);
+}
+#endif
+
+dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
+{
+ siginfo_t info;
+ local_irq_enable();
+
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_BADSTK;
+ info.si_addr = 0;
+ if (notify_die(DIE_TRAP, "iret exception",
+ regs, error_code, 32, SIGILL) == NOTIFY_STOP)
+ return;
+ do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
+}
+#endif
+
void __init trap_init(void)
{
+#ifdef CONFIG_X86_32
int i;
+#endif
#ifdef CONFIG_EISA
void __iomem *p = early_ioremap(0x0FFFD9, 4);
@@ -1185,29 +969,40 @@ void __init trap_init(void)
early_iounmap(p, 4);
#endif
- set_trap_gate(0, &divide_error);
- set_intr_gate(1, &debug);
- set_intr_gate(2, &nmi);
- set_system_intr_gate(3, &int3); /* int3 can be called from all */
- set_system_gate(4, &overflow); /* int4 can be called from all */
- set_trap_gate(5, &bounds);
- set_trap_gate(6, &invalid_op);
- set_trap_gate(7, &device_not_available);
+ set_intr_gate(0, &divide_error);
+ set_intr_gate_ist(1, &debug, DEBUG_STACK);
+ set_intr_gate_ist(2, &nmi, NMI_STACK);
+ /* int3 can be called from all */
+ set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
+ /* int4 can be called from all */
+ set_system_intr_gate(4, &overflow);
+ set_intr_gate(5, &bounds);
+ set_intr_gate(6, &invalid_op);
+ set_intr_gate(7, &device_not_available);
+#ifdef CONFIG_X86_32
set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
- set_trap_gate(9, &coprocessor_segment_overrun);
- set_trap_gate(10, &invalid_TSS);
- set_trap_gate(11, &segment_not_present);
- set_trap_gate(12, &stack_segment);
- set_trap_gate(13, &general_protection);
+#else
+ set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+#endif
+ set_intr_gate(9, &coprocessor_segment_overrun);
+ set_intr_gate(10, &invalid_TSS);
+ set_intr_gate(11, &segment_not_present);
+ set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
+ set_intr_gate(13, &general_protection);
set_intr_gate(14, &page_fault);
- set_trap_gate(15, &spurious_interrupt_bug);
- set_trap_gate(16, &coprocessor_error);
- set_trap_gate(17, &alignment_check);
+ set_intr_gate(15, &spurious_interrupt_bug);
+ set_intr_gate(16, &coprocessor_error);
+ set_intr_gate(17, &alignment_check);
#ifdef CONFIG_X86_MCE
- set_trap_gate(18, &machine_check);
+ set_intr_gate_ist(18, &machine_check, MCE_STACK);
#endif
- set_trap_gate(19, &simd_coprocessor_error);
+ set_intr_gate(19, &simd_coprocessor_error);
+#ifdef CONFIG_IA32_EMULATION
+ set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
+#endif
+
+#ifdef CONFIG_X86_32
if (cpu_has_fxsr) {
printk(KERN_INFO "Enabling fast FPU save and restore... ");
set_in_cr4(X86_CR4_OSFXSR);
@@ -1220,36 +1015,20 @@ void __init trap_init(void)
printk("done.\n");
}
- set_system_gate(SYSCALL_VECTOR, &system_call);
+ set_system_trap_gate(SYSCALL_VECTOR, &system_call);
/* Reserve all the builtin and the syscall vector: */
for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
set_bit(i, used_vectors);
set_bit(SYSCALL_VECTOR, used_vectors);
-
+#endif
/*
* Should be a barrier for any external CPU state:
*/
cpu_init();
+#ifdef CONFIG_X86_32
trap_init_hook();
+#endif
}
-
-static int __init kstack_setup(char *s)
-{
- kstack_depth_to_print = simple_strtoul(s, NULL, 0);
-
- return 1;
-}
-__setup("kstack=", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
- code_bytes = simple_strtoul(s, NULL, 0);
- if (code_bytes > 8192)
- code_bytes = 8192;
-
- return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
deleted file mode 100644
index 2887a789e38..00000000000
--- a/arch/x86/kernel/traps_64.c
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
- *
- * Pentium III FXSR, SSE support
- * Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'entry.S'.
- */
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/kallsyms.h>
-#include <linux/spinlock.h>
-#include <linux/kprobes.h>
-#include <linux/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/kdebug.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/unwind.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/kexec.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/bug.h>
-#include <linux/nmi.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-
-#if defined(CONFIG_EDAC)
-#include <linux/edac.h>
-#endif
-
-#include <asm/stacktrace.h>
-#include <asm/processor.h>
-#include <asm/debugreg.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-#include <asm/unwind.h>
-#include <asm/desc.h>
-#include <asm/i387.h>
-#include <asm/pgalloc.h>
-#include <asm/proto.h>
-#include <asm/pda.h>
-#include <asm/traps.h>
-
-#include <mach_traps.h>
-
-int panic_on_unrecovered_nmi;
-int kstack_depth_to_print = 12;
-static unsigned int code_bytes = 64;
-static int ignore_nmis;
-static int die_counter;
-
-static inline void conditional_sti(struct pt_regs *regs)
-{
- if (regs->flags & X86_EFLAGS_IF)
- local_irq_enable();
-}
-
-static inline void preempt_conditional_sti(struct pt_regs *regs)
-{
- inc_preempt_count();
- if (regs->flags & X86_EFLAGS_IF)
- local_irq_enable();
-}
-
-static inline void preempt_conditional_cli(struct pt_regs *regs)
-{
- if (regs->flags & X86_EFLAGS_IF)
- local_irq_disable();
- /* Make sure to not schedule here because we could be running
- on an exception stack. */
- dec_preempt_count();
-}
-
-void printk_address(unsigned long address, int reliable)
-{
- printk(" [<%016lx>] %s%pS\n",
- address, reliable ? "" : "? ", (void *) address);
-}
-
-static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
- unsigned *usedp, char **idp)
-{
- static char ids[][8] = {
- [DEBUG_STACK - 1] = "#DB",
- [NMI_STACK - 1] = "NMI",
- [DOUBLEFAULT_STACK - 1] = "#DF",
- [STACKFAULT_STACK - 1] = "#SS",
- [MCE_STACK - 1] = "#MC",
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
- [N_EXCEPTION_STACKS ...
- N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
-#endif
- };
- unsigned k;
-
- /*
- * Iterate over all exception stacks, and figure out whether
- * 'stack' is in one of them:
- */
- for (k = 0; k < N_EXCEPTION_STACKS; k++) {
- unsigned long end = per_cpu(orig_ist, cpu).ist[k];
- /*
- * Is 'stack' above this exception frame's end?
- * If yes then skip to the next frame.
- */
- if (stack >= end)
- continue;
- /*
- * Is 'stack' above this exception frame's start address?
- * If yes then we found the right frame.
- */
- if (stack >= end - EXCEPTION_STKSZ) {
- /*
- * Make sure we only iterate through an exception
- * stack once. If it comes up for the second time
- * then there's something wrong going on - just
- * break out and return NULL:
- */
- if (*usedp & (1U << k))
- break;
- *usedp |= 1U << k;
- *idp = ids[k];
- return (unsigned long *)end;
- }
- /*
- * If this is a debug stack, and if it has a larger size than
- * the usual exception stacks, then 'stack' might still
- * be within the lower portion of the debug stack:
- */
-#if DEBUG_STKSZ > EXCEPTION_STKSZ
- if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
- unsigned j = N_EXCEPTION_STACKS - 1;
-
- /*
- * Black magic. A large debug stack is composed of
- * multiple exception stack entries, which we
- * iterate through now. Dont look:
- */
- do {
- ++j;
- end -= EXCEPTION_STKSZ;
- ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
- } while (stack < end - EXCEPTION_STKSZ);
- if (*usedp & (1U << j))
- break;
- *usedp |= 1U << j;
- *idp = ids[j];
- return (unsigned long *)end;
- }
-#endif
- }
- return NULL;
-}
-
-/*
- * x86-64 can have up to three kernel stacks:
- * process stack
- * interrupt stack
- * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
- */
-
-static inline int valid_stack_ptr(struct thread_info *tinfo,
- void *p, unsigned int size, void *end)
-{
- void *t = tinfo;
- if (end) {
- if (p < end && p >= (end-THREAD_SIZE))
- return 1;
- else
- return 0;
- }
- return p > t && p < t + THREAD_SIZE - size;
-}
-
-/* The form of the top of the frame on the stack */
-struct stack_frame {
- struct stack_frame *next_frame;
- unsigned long return_address;
-};
-
-static inline unsigned long
-print_context_stack(struct thread_info *tinfo,
- unsigned long *stack, unsigned long bp,
- const struct stacktrace_ops *ops, void *data,
- unsigned long *end)
-{
- struct stack_frame *frame = (struct stack_frame *)bp;
-
- while (valid_stack_ptr(tinfo, stack, sizeof(*stack), end)) {
- unsigned long addr;
-
- addr = *stack;
- if (__kernel_text_address(addr)) {
- if ((unsigned long) stack == bp + 8) {
- ops->address(data, addr, 1);
- frame = frame->next_frame;
- bp = (unsigned long) frame;
- } else {
- ops->address(data, addr, bp == 0);
- }
- }
- stack++;
- }
- return bp;
-}
-
-void dump_trace(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, unsigned long bp,
- const struct stacktrace_ops *ops, void *data)
-{
- const unsigned cpu = get_cpu();
- unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
- unsigned used = 0;
- struct thread_info *tinfo;
-
- if (!task)
- task = current;
-
- if (!stack) {
- unsigned long dummy;
- stack = &dummy;
- if (task && task != current)
- stack = (unsigned long *)task->thread.sp;
- }
-
-#ifdef CONFIG_FRAME_POINTER
- if (!bp) {
- if (task == current) {
- /* Grab bp right from our regs */
- asm("movq %%rbp, %0" : "=r" (bp) : );
- } else {
- /* bp is the last reg pushed by switch_to */
- bp = *(unsigned long *) task->thread.sp;
- }
- }
-#endif
-
- /*
- * Print function call entries in all stacks, starting at the
- * current stack address. If the stacks consist of nested
- * exceptions
- */
- tinfo = task_thread_info(task);
- for (;;) {
- char *id;
- unsigned long *estack_end;
- estack_end = in_exception_stack(cpu, (unsigned long)stack,
- &used, &id);
-
- if (estack_end) {
- if (ops->stack(data, id) < 0)
- break;
-
- bp = print_context_stack(tinfo, stack, bp, ops,
- data, estack_end);
- ops->stack(data, "<EOE>");
- /*
- * We link to the next stack via the
- * second-to-last pointer (index -2 to end) in the
- * exception stack:
- */
- stack = (unsigned long *) estack_end[-2];
- continue;
- }
- if (irqstack_end) {
- unsigned long *irqstack;
- irqstack = irqstack_end -
- (IRQSTACKSIZE - 64) / sizeof(*irqstack);
-
- if (stack >= irqstack && stack < irqstack_end) {
- if (ops->stack(data, "IRQ") < 0)
- break;
- bp = print_context_stack(tinfo, stack, bp,
- ops, data, irqstack_end);
- /*
- * We link to the next stack (which would be
- * the process stack normally) the last
- * pointer (index -1 to end) in the IRQ stack:
- */
- stack = (unsigned long *) (irqstack_end[-1]);
- irqstack_end = NULL;
- ops->stack(data, "EOI");
- continue;
- }
- }
- break;
- }
-
- /*
- * This handles the process stack:
- */
- bp = print_context_stack(tinfo, stack, bp, ops, data, NULL);
- put_cpu();
-}
-EXPORT_SYMBOL(dump_trace);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
- print_symbol(msg, symbol);
- printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
- printk("%s\n", msg);
-}
-
-static int print_trace_stack(void *data, char *name)
-{
- printk(" <%s> ", name);
- return 0;
-}
-
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
- touch_nmi_watchdog();
- printk_address(addr, reliable);
-}
-
-static const struct stacktrace_ops print_trace_ops = {
- .warning = print_trace_warning,
- .warning_symbol = print_trace_warning_symbol,
- .stack = print_trace_stack,
- .address = print_trace_address,
-};
-
-static void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, unsigned long bp, char *log_lvl)
-{
- printk("Call Trace:\n");
- dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-}
-
-void show_trace(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, unsigned long bp)
-{
- show_trace_log_lvl(task, regs, stack, bp, "");
-}
-
-static void
-show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, unsigned long bp, char *log_lvl)
-{
- unsigned long *stack;
- int i;
- const int cpu = smp_processor_id();
- unsigned long *irqstack_end =
- (unsigned long *) (cpu_pda(cpu)->irqstackptr);
- unsigned long *irqstack =
- (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE);
-
- /*
- * debugging aid: "show_stack(NULL, NULL);" prints the
- * back trace for this cpu.
- */
-
- if (sp == NULL) {
- if (task)
- sp = (unsigned long *)task->thread.sp;
- else
- sp = (unsigned long *)&sp;
- }
-
- stack = sp;
- for (i = 0; i < kstack_depth_to_print; i++) {
- if (stack >= irqstack && stack <= irqstack_end) {
- if (stack == irqstack_end) {
- stack = (unsigned long *) (irqstack_end[-1]);
- printk(" <EOI> ");
- }
- } else {
- if (((long) stack & (THREAD_SIZE-1)) == 0)
- break;
- }
- if (i && ((i % 4) == 0))
- printk("\n");
- printk(" %016lx", *stack++);
- touch_nmi_watchdog();
- }
- printk("\n");
- show_trace_log_lvl(task, regs, sp, bp, log_lvl);
-}
-
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
- show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
- unsigned long bp = 0;
- unsigned long stack;
-
-#ifdef CONFIG_FRAME_POINTER
- if (!bp)
- asm("movq %%rbp, %0" : "=r" (bp) : );
-#endif
-
- printk("Pid: %d, comm: %.20s %s %s %.*s\n",
- current->pid, current->comm, print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
- show_trace(NULL, NULL, &stack, bp);
-}
-EXPORT_SYMBOL(dump_stack);
-
-void show_registers(struct pt_regs *regs)
-{
- int i;
- unsigned long sp;
- const int cpu = smp_processor_id();
- struct task_struct *cur = cpu_pda(cpu)->pcurrent;
-
- sp = regs->sp;
- printk("CPU %d ", cpu);
- __show_regs(regs);
- printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
- cur->comm, cur->pid, task_thread_info(cur), cur);
-
- /*
- * When in-kernel, we also print out the stack and code at the
- * time of the fault..
- */
- if (!user_mode(regs)) {
- unsigned int code_prologue = code_bytes * 43 / 64;
- unsigned int code_len = code_bytes;
- unsigned char c;
- u8 *ip;
-
- printk("Stack: ");
- show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
- regs->bp, "");
-
- printk(KERN_EMERG "Code: ");
-
- ip = (u8 *)regs->ip - code_prologue;
- if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
- /* try starting at RIP */
- ip = (u8 *)regs->ip;
- code_len = code_len - code_prologue + 1;
- }
- for (i = 0; i < code_len; i++, ip++) {
- if (ip < (u8 *)PAGE_OFFSET ||
- probe_kernel_address(ip, c)) {
- printk(" Bad RIP value.");
- break;
- }
- if (ip == (u8 *)regs->ip)
- printk("<%02x> ", c);
- else
- printk("%02x ", c);
- }
- }
- printk("\n");
-}
-
-int is_valid_bugaddr(unsigned long ip)
-{
- unsigned short ud2;
-
- if (__copy_from_user(&ud2, (const void __user *) ip, sizeof(ud2)))
- return 0;
-
- return ud2 == 0x0b0f;
-}
-
-static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED;
-static int die_owner = -1;
-static unsigned int die_nest_count;
-
-unsigned __kprobes long oops_begin(void)
-{
- int cpu;
- unsigned long flags;
-
- oops_enter();
-
- /* racy, but better than risking deadlock. */
- raw_local_irq_save(flags);
- cpu = smp_processor_id();
- if (!__raw_spin_trylock(&die_lock)) {
- if (cpu == die_owner)
- /* nested oops. should stop eventually */;
- else
- __raw_spin_lock(&die_lock);
- }
- die_nest_count++;
- die_owner = cpu;
- console_verbose();
- bust_spinlocks(1);
- return flags;
-}
-
-void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
-{
- die_owner = -1;
- bust_spinlocks(0);
- die_nest_count--;
- if (!die_nest_count)
- /* Nest count reaches zero, release the lock. */
- __raw_spin_unlock(&die_lock);
- raw_local_irq_restore(flags);
- if (!regs) {
- oops_exit();
- return;
- }
- if (panic_on_oops)
- panic("Fatal exception");
- oops_exit();
- do_exit(signr);
-}
-
-int __kprobes __die(const char *str, struct pt_regs *regs, long err)
-{
- printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
- printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
- printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
- printk("DEBUG_PAGEALLOC");
-#endif
- printk("\n");
- if (notify_die(DIE_OOPS, str, regs, err,
- current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
- return 1;
-
- show_registers(regs);
- add_taint(TAINT_DIE);
- /* Executive summary in case the oops scrolled away */
- printk(KERN_ALERT "RIP ");
- printk_address(regs->ip, 1);
- printk(" RSP <%016lx>\n", regs->sp);
- if (kexec_should_crash(current))
- crash_kexec(regs);
- return 0;
-}
-
-void die(const char *str, struct pt_regs *regs, long err)
-{
- unsigned long flags = oops_begin();
-
- if (!user_mode(regs))
- report_bug(regs->ip, regs);
-
- if (__die(str, regs, err))
- regs = NULL;
- oops_end(flags, regs, SIGSEGV);
-}
-
-notrace __kprobes void
-die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
- unsigned long flags;
-
- if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
- return;
-
- flags = oops_begin();
- /*
- * We are in trouble anyway, lets at least try
- * to get a message out.
- */
- printk(KERN_EMERG "%s", str);
- printk(" on CPU%d, ip %08lx, registers:\n",
- smp_processor_id(), regs->ip);
- show_registers(regs);
- if (kexec_should_crash(current))
- crash_kexec(regs);
- if (do_panic || panic_on_oops)
- panic("Non maskable interrupt");
- oops_end(flags, NULL, SIGBUS);
- nmi_exit();
- local_irq_enable();
- do_exit(SIGBUS);
-}
-
-static void __kprobes
-do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
- long error_code, siginfo_t *info)
-{
- struct task_struct *tsk = current;
-
- if (!user_mode(regs))
- goto kernel_trap;
-
- /*
- * We want error_code and trap_no set for userspace faults and
- * kernelspace faults which result in die(), but not
- * kernelspace faults which are fixed up. die() gives the
- * process no chance to handle the signal and notice the
- * kernel fault information, so that won't result in polluting
- * the information about previously queued, but not yet
- * delivered, faults. See also do_general_protection below.
- */
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = trapnr;
-
- if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
- printk_ratelimit()) {
- printk(KERN_INFO
- "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
- tsk->comm, tsk->pid, str,
- regs->ip, regs->sp, error_code);
- print_vma_addr(" in ", regs->ip);
- printk("\n");
- }
-
- if (info)
- force_sig_info(signr, info, tsk);
- else
- force_sig(signr, tsk);
- return;
-
-kernel_trap:
- if (!fixup_exception(regs)) {
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = trapnr;
- die(str, regs, error_code);
- }
- return;
-}
-
-#define DO_ERROR(trapnr, signr, str, name) \
-asmlinkage void do_##name(struct pt_regs *regs, long error_code) \
-{ \
- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- == NOTIFY_STOP) \
- return; \
- conditional_sti(regs); \
- do_trap(trapnr, signr, str, regs, error_code, NULL); \
-}
-
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
-asmlinkage void do_##name(struct pt_regs *regs, long error_code) \
-{ \
- siginfo_t info; \
- info.si_signo = signr; \
- info.si_errno = 0; \
- info.si_code = sicode; \
- info.si_addr = (void __user *)siaddr; \
- trace_hardirqs_fixup(); \
- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- == NOTIFY_STOP) \
- return; \
- conditional_sti(regs); \
- do_trap(trapnr, signr, str, regs, error_code, &info); \
-}
-
-DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
-DO_ERROR(4, SIGSEGV, "overflow", overflow)
-DO_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
-DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-
-/* Runs on IST stack */
-asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code)
-{
- if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
- 12, SIGBUS) == NOTIFY_STOP)
- return;
- preempt_conditional_sti(regs);
- do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
- preempt_conditional_cli(regs);
-}
-
-asmlinkage void do_double_fault(struct pt_regs *regs, long error_code)
-{
- static const char str[] = "double fault";
- struct task_struct *tsk = current;
-
- /* Return not checked because double check cannot be ignored */
- notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
-
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 8;
-
- /* This is always a kernel trap and never fixable (and thus must
- never return). */
- for (;;)
- die(str, regs, error_code);
-}
-
-asmlinkage void __kprobes
-do_general_protection(struct pt_regs *regs, long error_code)
-{
- struct task_struct *tsk;
-
- conditional_sti(regs);
-
- tsk = current;
- if (!user_mode(regs))
- goto gp_in_kernel;
-
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 13;
-
- if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
- printk_ratelimit()) {
- printk(KERN_INFO
- "%s[%d] general protection ip:%lx sp:%lx error:%lx",
- tsk->comm, tsk->pid,
- regs->ip, regs->sp, error_code);
- print_vma_addr(" in ", regs->ip);
- printk("\n");
- }
-
- force_sig(SIGSEGV, tsk);
- return;
-
-gp_in_kernel:
- if (fixup_exception(regs))
- return;
-
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 13;
- if (notify_die(DIE_GPF, "general protection fault", regs,
- error_code, 13, SIGSEGV) == NOTIFY_STOP)
- return;
- die("general protection fault", regs, error_code);
-}
-
-static notrace __kprobes void
-mem_parity_error(unsigned char reason, struct pt_regs *regs)
-{
- printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
- reason);
- printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
-
-#if defined(CONFIG_EDAC)
- if (edac_handler_set()) {
- edac_atomic_assert_error();
- return;
- }
-#endif
-
- if (panic_on_unrecovered_nmi)
- panic("NMI: Not continuing");
-
- printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-
- /* Clear and disable the memory parity error line. */
- reason = (reason & 0xf) | 4;
- outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-io_check_error(unsigned char reason, struct pt_regs *regs)
-{
- printk("NMI: IOCK error (debug interrupt?)\n");
- show_registers(regs);
-
- /* Re-enable the IOCK line, wait for a few seconds */
- reason = (reason & 0xf) | 8;
- outb(reason, 0x61);
- mdelay(2000);
- reason &= ~8;
- outb(reason, 0x61);
-}
-
-static notrace __kprobes void
-unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
-{
- if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
- NOTIFY_STOP)
- return;
- printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
- reason);
- printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
-
- if (panic_on_unrecovered_nmi)
- panic("NMI: Not continuing");
-
- printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-}
-
-/* Runs on IST stack. This code must keep interrupts off all the time.
- Nested NMIs are prevented by the CPU. */
-asmlinkage notrace __kprobes void default_do_nmi(struct pt_regs *regs)
-{
- unsigned char reason = 0;
- int cpu;
-
- cpu = smp_processor_id();
-
- /* Only the BSP gets external NMIs from the system. */
- if (!cpu)
- reason = get_nmi_reason();
-
- if (!(reason & 0xc0)) {
- if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
- == NOTIFY_STOP)
- return;
- /*
- * Ok, so this is none of the documented NMI sources,
- * so it must be the NMI watchdog.
- */
- if (nmi_watchdog_tick(regs, reason))
- return;
- if (!do_nmi_callback(regs, cpu))
- unknown_nmi_error(reason, regs);
-
- return;
- }
- if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
- return;
-
- /* AK: following checks seem to be broken on modern chipsets. FIXME */
- if (reason & 0x80)
- mem_parity_error(reason, regs);
- if (reason & 0x40)
- io_check_error(reason, regs);
-}
-
-asmlinkage notrace __kprobes void
-do_nmi(struct pt_regs *regs, long error_code)
-{
- nmi_enter();
-
- add_pda(__nmi_count, 1);
-
- if (!ignore_nmis)
- default_do_nmi(regs);
-
- nmi_exit();
-}
-
-void stop_nmi(void)
-{
- acpi_nmi_disable();
- ignore_nmis++;
-}
-
-void restart_nmi(void)
-{
- ignore_nmis--;
- acpi_nmi_enable();
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
-{
- trace_hardirqs_fixup();
-
- if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
- == NOTIFY_STOP)
- return;
-
- preempt_conditional_sti(regs);
- do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
- preempt_conditional_cli(regs);
-}
-
-/* Help handler running on IST stack to switch back to user stack
- for scheduling or signal handling. The actual stack switch is done in
- entry.S */
-asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
-{
- struct pt_regs *regs = eregs;
- /* Did already sync */
- if (eregs == (struct pt_regs *)eregs->sp)
- ;
- /* Exception from user space */
- else if (user_mode(eregs))
- regs = task_pt_regs(current);
- /* Exception from kernel and interrupts are enabled. Move to
- kernel process stack. */
- else if (eregs->flags & X86_EFLAGS_IF)
- regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
- if (eregs != regs)
- *regs = *eregs;
- return regs;
-}
-
-/* runs on IST stack. */
-asmlinkage void __kprobes do_debug(struct pt_regs *regs,
- unsigned long error_code)
-{
- struct task_struct *tsk = current;
- unsigned long condition;
- siginfo_t info;
-
- trace_hardirqs_fixup();
-
- get_debugreg(condition, 6);
-
- /*
- * The processor cleared BTF, so don't mark that we need it set.
- */
- clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
- tsk->thread.debugctlmsr = 0;
-
- if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
- SIGTRAP) == NOTIFY_STOP)
- return;
-
- preempt_conditional_sti(regs);
-
- /* Mask out spurious debug traps due to lazy DR7 setting */
- if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
- if (!tsk->thread.debugreg7)
- goto clear_dr7;
- }
-
- tsk->thread.debugreg6 = condition;
-
- /*
- * Single-stepping through TF: make sure we ignore any events in
- * kernel space (but re-enable TF when returning to user mode).
- */
- if (condition & DR_STEP) {
- if (!user_mode(regs))
- goto clear_TF_reenable;
- }
-
- /* Ok, finally something we can handle */
- tsk->thread.trap_no = 1;
- tsk->thread.error_code = error_code;
- info.si_signo = SIGTRAP;
- info.si_errno = 0;
- info.si_code = TRAP_BRKPT;
- info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
- force_sig_info(SIGTRAP, &info, tsk);
-
-clear_dr7:
- set_debugreg(0, 7);
- preempt_conditional_cli(regs);
- return;
-
-clear_TF_reenable:
- set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
- regs->flags &= ~X86_EFLAGS_TF;
- preempt_conditional_cli(regs);
- return;
-}
-
-static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
-{
- if (fixup_exception(regs))
- return 1;
-
- notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
- /* Illegal floating point operation in the kernel */
- current->thread.trap_no = trapnr;
- die(str, regs, 0);
- return 0;
-}
-
-/*
- * Note that we play around with the 'TS' bit in an attempt to get
- * the correct behaviour even in the presence of the asynchronous
- * IRQ13 behaviour
- */
-asmlinkage void do_coprocessor_error(struct pt_regs *regs)
-{
- void __user *ip = (void __user *)(regs->ip);
- struct task_struct *task;
- siginfo_t info;
- unsigned short cwd, swd;
-
- conditional_sti(regs);
- if (!user_mode(regs) &&
- kernel_math_error(regs, "kernel x87 math error", 16))
- return;
-
- /*
- * Save the info for the exception handler and clear the error.
- */
- task = current;
- save_init_fpu(task);
- task->thread.trap_no = 16;
- task->thread.error_code = 0;
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_code = __SI_FAULT;
- info.si_addr = ip;
- /*
- * (~cwd & swd) will mask out exceptions that are not set to unmasked
- * status. 0x3f is the exception bits in these regs, 0x200 is the
- * C1 reg you need in case of a stack fault, 0x040 is the stack
- * fault bit. We should only be taking one exception at a time,
- * so if this combination doesn't produce any single exception,
- * then we have a bad program that isn't synchronizing its FPU usage
- * and it will suffer the consequences since we won't be able to
- * fully reproduce the context of the exception
- */
- cwd = get_fpu_cwd(task);
- swd = get_fpu_swd(task);
- switch (swd & ~cwd & 0x3f) {
- case 0x000: /* No unmasked exception */
- default: /* Multiple exceptions */
- break;
- case 0x001: /* Invalid Op */
- /*
- * swd & 0x240 == 0x040: Stack Underflow
- * swd & 0x240 == 0x240: Stack Overflow
- * User must clear the SF bit (0x40) if set
- */
- info.si_code = FPE_FLTINV;
- break;
- case 0x002: /* Denormalize */
- case 0x010: /* Underflow */
- info.si_code = FPE_FLTUND;
- break;
- case 0x004: /* Zero Divide */
- info.si_code = FPE_FLTDIV;
- break;
- case 0x008: /* Overflow */
- info.si_code = FPE_FLTOVF;
- break;
- case 0x020: /* Precision */
- info.si_code = FPE_FLTRES;
- break;
- }
- force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void bad_intr(void)
-{
- printk("bad interrupt");
-}
-
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
-{
- void __user *ip = (void __user *)(regs->ip);
- struct task_struct *task;
- siginfo_t info;
- unsigned short mxcsr;
-
- conditional_sti(regs);
- if (!user_mode(regs) &&
- kernel_math_error(regs, "kernel simd math error", 19))
- return;
-
- /*
- * Save the info for the exception handler and clear the error.
- */
- task = current;
- save_init_fpu(task);
- task->thread.trap_no = 19;
- task->thread.error_code = 0;
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_code = __SI_FAULT;
- info.si_addr = ip;
- /*
- * The SIMD FPU exceptions are handled a little differently, as there
- * is only a single status/control register. Thus, to determine which
- * unmasked exception was caught we must mask the exception mask bits
- * at 0x1f80, and then use these to mask the exception bits at 0x3f.
- */
- mxcsr = get_fpu_mxcsr(task);
- switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
- case 0x000:
- default:
- break;
- case 0x001: /* Invalid Op */
- info.si_code = FPE_FLTINV;
- break;
- case 0x002: /* Denormalize */
- case 0x010: /* Underflow */
- info.si_code = FPE_FLTUND;
- break;
- case 0x004: /* Zero Divide */
- info.si_code = FPE_FLTDIV;
- break;
- case 0x008: /* Overflow */
- info.si_code = FPE_FLTOVF;
- break;
- case 0x020: /* Precision */
- info.si_code = FPE_FLTRES;
- break;
- }
- force_sig_info(SIGFPE, &info, task);
-}
-
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs *regs)
-{
-}
-
-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
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- */
-asmlinkage void math_state_restore(void)
-{
- struct task_struct *me = current;
-
- if (!used_math()) {
- local_irq_enable();
- /*
- * does a slab alloc which can sleep
- */
- if (init_fpu(me)) {
- /*
- * ran out of memory!
- */
- do_group_exit(SIGKILL);
- return;
- }
- local_irq_disable();
- }
-
- clts(); /* Allow maths ops (or we recurse) */
- /*
- * Paranoid restore. send a SIGSEGV if we fail to restore the state.
- */
- if (unlikely(restore_fpu_checking(me))) {
- stts();
- force_sig(SIGSEGV, me);
- return;
- }
- task_thread_info(me)->status |= TS_USEDFPU;
- me->fpu_counter++;
-}
-EXPORT_SYMBOL_GPL(math_state_restore);
-
-void __init trap_init(void)
-{
- set_intr_gate(0, &divide_error);
- set_intr_gate_ist(1, &debug, DEBUG_STACK);
- set_intr_gate_ist(2, &nmi, NMI_STACK);
- /* int3 can be called from all */
- set_system_gate_ist(3, &int3, DEBUG_STACK);
- /* int4 can be called from all */
- set_system_gate(4, &overflow);
- set_intr_gate(5, &bounds);
- set_intr_gate(6, &invalid_op);
- set_intr_gate(7, &device_not_available);
- set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
- set_intr_gate(9, &coprocessor_segment_overrun);
- set_intr_gate(10, &invalid_TSS);
- set_intr_gate(11, &segment_not_present);
- set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
- set_intr_gate(13, &general_protection);
- set_intr_gate(14, &page_fault);
- set_intr_gate(15, &spurious_interrupt_bug);
- set_intr_gate(16, &coprocessor_error);
- set_intr_gate(17, &alignment_check);
-#ifdef CONFIG_X86_MCE
- set_intr_gate_ist(18, &machine_check, MCE_STACK);
-#endif
- set_intr_gate(19, &simd_coprocessor_error);
-
-#ifdef CONFIG_IA32_EMULATION
- set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
-#endif
- /*
- * Should be a barrier for any external CPU state:
- */
- cpu_init();
-}
-
-static int __init oops_setup(char *s)
-{
- if (!s)
- return -EINVAL;
- if (!strcmp(s, "panic"))
- panic_on_oops = 1;
- return 0;
-}
-early_param("oops", oops_setup);
-
-static int __init kstack_setup(char *s)
-{
- if (!s)
- return -EINVAL;
- kstack_depth_to_print = simple_strtoul(s, NULL, 0);
- return 0;
-}
-early_param("kstack", kstack_setup);
-
-static int __init code_bytes_setup(char *s)
-{
- code_bytes = simple_strtoul(s, NULL, 0);
- if (code_bytes > 8192)
- code_bytes = 8192;
-
- return 1;
-}
-__setup("code_bytes=", code_bytes_setup);
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
index 201e81a91a9..46e05447405 100644
--- a/arch/x86/kernel/vmlinux_64.lds.S
+++ b/arch/x86/kernel/vmlinux_64.lds.S
@@ -172,8 +172,8 @@ SECTIONS
.x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
*(.x86_cpu_dev.init)
}
- SECURITY_INIT
__x86_cpu_dev_end = .;
+ SECURITY_INIT
. = ALIGN(8);
.parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 07713d64deb..9abac8a9d82 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -95,7 +95,9 @@ int save_i387_xstate(void __user *buf)
* Start with clearing the user buffer. This will present a
* clean context for the bytes not touched by the fxsave/xsave.
*/
- __clear_user(buf, sig_xstate_size);
+ err = __clear_user(buf, sig_xstate_size);
+ if (err)
+ return err;
if (task_thread_info(tsk)->status & TS_XSAVE)
err = xsave_user(buf);
@@ -114,6 +116,8 @@ int save_i387_xstate(void __user *buf)
if (task_thread_info(tsk)->status & TS_XSAVE) {
struct _fpstate __user *fx = buf;
+ struct _xstate __user *x = buf;
+ u64 xstate_bv;
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
sizeof(struct _fpx_sw_bytes));
@@ -121,6 +125,31 @@ int save_i387_xstate(void __user *buf)
err |= __put_user(FP_XSTATE_MAGIC2,
(__u32 __user *) (buf + sig_xstate_size
- FP_XSTATE_MAGIC2_SIZE));
+
+ /*
+ * Read the xstate_bv which we copied (directly from the cpu or
+ * from the state in task struct) to the user buffers and
+ * set the FP/SSE bits.
+ */
+ err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+ /*
+ * For legacy compatible, we always set FP/SSE bits in the bit
+ * vector while saving the state to the user context. This will
+ * enable us capturing any changes(during sigreturn) to
+ * the FP/SSE bits by the legacy applications which don't touch
+ * xstate_bv in the xsave header.
+ *
+ * xsave aware apps can change the xstate_bv in the xsave
+ * header as well as change any contents in the memory layout.
+ * xrestore as part of sigreturn will capture all the changes.
+ */
+ xstate_bv |= XSTATE_FPSSE;
+
+ err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+ if (err)
+ return err;
}
return 1;
@@ -272,7 +301,7 @@ void __cpuinit xsave_init(void)
/*
* setup the xstate image representing the init state
*/
-void setup_xstate_init(void)
+static void __init setup_xstate_init(void)
{
init_xstate_buf = alloc_bootmem(xstate_size);
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
diff --git a/arch/x86/mach-generic/es7000.c b/arch/x86/mach-generic/es7000.c
index 520cca0ee04..6513d41ea21 100644
--- a/arch/x86/mach-generic/es7000.c
+++ b/arch/x86/mach-generic/es7000.c
@@ -47,16 +47,26 @@ static __init int mps_oem_check(struct mp_config_table *mpc, char *oem,
/* Hook from generic ACPI tables.c */
static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
- unsigned long oem_addr;
+ unsigned long oem_addr = 0;
+ int check_dsdt;
+ int ret = 0;
+
+ /* check dsdt at first to avoid clear fix_map for oem_addr */
+ check_dsdt = es7000_check_dsdt();
+
if (!find_unisys_acpi_oem_table(&oem_addr)) {
- if (es7000_check_dsdt())
- return parse_unisys_oem((char *)oem_addr);
+ if (check_dsdt)
+ ret = parse_unisys_oem((char *)oem_addr);
else {
setup_unisys();
- return 1;
+ ret = 1;
}
+ /*
+ * we need to unmap it
+ */
+ unmap_unisys_acpi_oem_table(oem_addr);
}
- return 0;
+ return ret;
}
#else
static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index dfb932dcf13..59f89b434b4 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -13,12 +13,8 @@ obj-$(CONFIG_MMIOTRACE) += mmiotrace.o
mmiotrace-y := pf_in.o mmio-mod.o
obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o
-ifeq ($(CONFIG_X86_32),y)
-obj-$(CONFIG_NUMA) += discontig_32.o
-else
-obj-$(CONFIG_NUMA) += numa_64.o
+obj-$(CONFIG_NUMA) += numa_$(BITS).o
obj-$(CONFIG_K8_NUMA) += k8topology_64.o
-endif
obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o
obj-$(CONFIG_MEMTEST) += memtest.o
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 8f92cac4e6d..3f2b8962cbd 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -592,11 +592,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
unsigned long flags;
#endif
- /*
- * We can fault from pretty much anywhere, with unknown IRQ state.
- */
- trace_hardirqs_fixup();
-
tsk = current;
mm = tsk->mm;
prefetchw(&mm->mmap_sem);
@@ -914,15 +909,15 @@ LIST_HEAD(pgd_list);
void vmalloc_sync_all(void)
{
-#ifdef CONFIG_X86_32
- unsigned long start = VMALLOC_START & PGDIR_MASK;
unsigned long address;
+#ifdef CONFIG_X86_32
if (SHARED_KERNEL_PMD)
return;
- BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
- for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
+ for (address = VMALLOC_START & PMD_MASK;
+ address >= TASK_SIZE && address < FIXADDR_TOP;
+ address += PMD_SIZE) {
unsigned long flags;
struct page *page;
@@ -935,10 +930,8 @@ void vmalloc_sync_all(void)
spin_unlock_irqrestore(&pgd_lock, flags);
}
#else /* CONFIG_X86_64 */
- unsigned long start = VMALLOC_START & PGDIR_MASK;
- unsigned long address;
-
- for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
+ for (address = VMALLOC_START & PGDIR_MASK; address <= VMALLOC_END;
+ address += PGDIR_SIZE) {
const pgd_t *pgd_ref = pgd_offset_k(address);
unsigned long flags;
struct page *page;
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index 007bb06c750..4ba373c5b8c 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -82,7 +82,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
pte_t pte = gup_get_pte(ptep);
struct page *page;
- if ((pte_val(pte) & (mask | _PAGE_SPECIAL)) != mask) {
+ if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
pte_unmap(ptep);
return 0;
}
@@ -116,10 +116,10 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
mask = _PAGE_PRESENT|_PAGE_USER;
if (write)
mask |= _PAGE_RW;
- if ((pte_val(pte) & mask) != mask)
+ if ((pte_flags(pte) & mask) != mask)
return 0;
/* hugepages are never "special" */
- VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+ VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
refs = 0;
@@ -173,10 +173,10 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
mask = _PAGE_PRESENT|_PAGE_USER;
if (write)
mask |= _PAGE_RW;
- if ((pte_val(pte) & mask) != mask)
+ if ((pte_flags(pte) & mask) != mask)
return 0;
/* hugepages are never "special" */
- VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
+ VM_BUG_ON(pte_flags(pte) & _PAGE_SPECIAL);
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
refs = 0;
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index c3789bb1930..8396868e82c 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -31,6 +31,7 @@
#include <linux/cpumask.h>
#include <asm/asm.h>
+#include <asm/bios_ebda.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -557,7 +558,7 @@ void zap_low_mappings(void)
int nx_enabled;
-pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL);
+pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
EXPORT_SYMBOL_GPL(__supported_pte_mask);
#ifdef CONFIG_X86_PAE
@@ -969,6 +970,8 @@ void __init mem_init(void)
int codesize, reservedpages, datasize, initsize;
int tmp;
+ start_periodic_check_for_corruption();
+
#ifdef CONFIG_FLATMEM
BUG_ON(!mem_map);
#endif
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 83e13f2d53d..b8e461d4941 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -31,6 +31,7 @@
#include <linux/nmi.h>
#include <asm/processor.h>
+#include <asm/bios_ebda.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -88,7 +89,7 @@ early_param("gbpages", parse_direct_gbpages_on);
int after_bootmem;
-unsigned long __supported_pte_mask __read_mostly = ~0UL;
+pteval_t __supported_pte_mask __read_mostly = ~_PAGE_IOMAP;
EXPORT_SYMBOL_GPL(__supported_pte_mask);
static int do_not_nx __cpuinitdata;
@@ -195,9 +196,6 @@ set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte)
}
pte = pte_offset_kernel(pmd, vaddr);
- if (!pte_none(*pte) && pte_val(new_pte) &&
- pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask))
- pte_ERROR(*pte);
set_pte(pte, new_pte);
/*
@@ -312,7 +310,7 @@ static __ref void *alloc_low_page(unsigned long *phys)
if (pfn >= table_top)
panic("alloc_low_page: ran out of memory");
- adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
+ adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
memset(adr, 0, PAGE_SIZE);
*phys = pfn * PAGE_SIZE;
return adr;
@@ -748,7 +746,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
old_start = mr[i].start;
memmove(&mr[i], &mr[i+1],
(nr_range - 1 - i) * sizeof (struct map_range));
- mr[i].start = old_start;
+ mr[i--].start = old_start;
nr_range--;
}
@@ -881,6 +879,8 @@ void __init mem_init(void)
{
long codesize, reservedpages, datasize, initsize;
+ start_periodic_check_for_corruption();
+
pci_iommu_alloc();
/* clear_bss() already clear the empty_zero_page */
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 6ab3196d12b..e4c43ec71b2 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -24,18 +24,47 @@
#ifdef CONFIG_X86_64
+static inline int phys_addr_valid(unsigned long addr)
+{
+ return addr < (1UL << boot_cpu_data.x86_phys_bits);
+}
+
unsigned long __phys_addr(unsigned long x)
{
- if (x >= __START_KERNEL_map)
- return x - __START_KERNEL_map + phys_base;
- return x - PAGE_OFFSET;
+ if (x >= __START_KERNEL_map) {
+ x -= __START_KERNEL_map;
+ VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE);
+ x += phys_base;
+ } else {
+ VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+ x -= PAGE_OFFSET;
+ VIRTUAL_BUG_ON(system_state == SYSTEM_BOOTING ? x > MAXMEM :
+ !phys_addr_valid(x));
+ }
+ return x;
}
EXPORT_SYMBOL(__phys_addr);
-static inline int phys_addr_valid(unsigned long addr)
+bool __virt_addr_valid(unsigned long x)
{
- return addr < (1UL << boot_cpu_data.x86_phys_bits);
+ if (x >= __START_KERNEL_map) {
+ x -= __START_KERNEL_map;
+ if (x >= KERNEL_IMAGE_SIZE)
+ return false;
+ x += phys_base;
+ } else {
+ if (x < PAGE_OFFSET)
+ return false;
+ x -= PAGE_OFFSET;
+ if (system_state == SYSTEM_BOOTING ?
+ x > MAXMEM : !phys_addr_valid(x)) {
+ return false;
+ }
+ }
+
+ return pfn_valid(x >> PAGE_SHIFT);
}
+EXPORT_SYMBOL(__virt_addr_valid);
#else
@@ -44,6 +73,28 @@ static inline int phys_addr_valid(unsigned long addr)
return 1;
}
+#ifdef CONFIG_DEBUG_VIRTUAL
+unsigned long __phys_addr(unsigned long x)
+{
+ /* VMALLOC_* aren't constants; not available at the boot time */
+ VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+ VIRTUAL_BUG_ON(system_state != SYSTEM_BOOTING &&
+ is_vmalloc_addr((void *) x));
+ return x - PAGE_OFFSET;
+}
+EXPORT_SYMBOL(__phys_addr);
+#endif
+
+bool __virt_addr_valid(unsigned long x)
+{
+ if (x < PAGE_OFFSET)
+ return false;
+ if (system_state != SYSTEM_BOOTING && is_vmalloc_addr((void *) x))
+ return false;
+ return pfn_valid((x - PAGE_OFFSET) >> PAGE_SHIFT);
+}
+EXPORT_SYMBOL(__virt_addr_valid);
+
#endif
int page_is_ram(unsigned long pagenr)
@@ -223,16 +274,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
switch (prot_val) {
case _PAGE_CACHE_UC:
default:
- prot = PAGE_KERNEL_NOCACHE;
+ prot = PAGE_KERNEL_IO_NOCACHE;
break;
case _PAGE_CACHE_UC_MINUS:
- prot = PAGE_KERNEL_UC_MINUS;
+ prot = PAGE_KERNEL_IO_UC_MINUS;
break;
case _PAGE_CACHE_WC:
- prot = PAGE_KERNEL_WC;
+ prot = PAGE_KERNEL_IO_WC;
break;
case _PAGE_CACHE_WB:
- prot = PAGE_KERNEL;
+ prot = PAGE_KERNEL_IO;
break;
}
@@ -549,12 +600,12 @@ static void __init __early_set_fixmap(enum fixed_addresses idx,
}
static inline void __init early_set_fixmap(enum fixed_addresses idx,
- unsigned long phys)
+ unsigned long phys, pgprot_t prot)
{
if (after_paging_init)
- set_fixmap(idx, phys);
+ __set_fixmap(idx, phys, prot);
else
- __early_set_fixmap(idx, phys, PAGE_KERNEL);
+ __early_set_fixmap(idx, phys, prot);
}
static inline void __init early_clear_fixmap(enum fixed_addresses idx)
@@ -565,16 +616,22 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx)
__early_set_fixmap(idx, 0, __pgprot(0));
}
-
-static int __initdata early_ioremap_nested;
-
+static void *prev_map[FIX_BTMAPS_SLOTS] __initdata;
+static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata;
static int __init check_early_ioremap_leak(void)
{
- if (!early_ioremap_nested)
+ int count = 0;
+ int i;
+
+ for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+ if (prev_map[i])
+ count++;
+
+ if (!count)
return 0;
WARN(1, KERN_WARNING
"Debug warning: early ioremap leak of %d areas detected.\n",
- early_ioremap_nested);
+ count);
printk(KERN_WARNING
"please boot with early_ioremap_debug and report the dmesg.\n");
@@ -582,18 +639,33 @@ static int __init check_early_ioremap_leak(void)
}
late_initcall(check_early_ioremap_leak);
-void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+static void __init *__early_ioremap(unsigned long phys_addr, unsigned long size, pgprot_t prot)
{
unsigned long offset, last_addr;
- unsigned int nrpages, nesting;
+ unsigned int nrpages;
enum fixed_addresses idx0, idx;
+ int i, slot;
WARN_ON(system_state != SYSTEM_BOOTING);
- nesting = early_ioremap_nested;
+ slot = -1;
+ for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+ if (!prev_map[i]) {
+ slot = i;
+ break;
+ }
+ }
+
+ if (slot < 0) {
+ printk(KERN_INFO "early_iomap(%08lx, %08lx) not found slot\n",
+ phys_addr, size);
+ WARN_ON(1);
+ return NULL;
+ }
+
if (early_ioremap_debug) {
printk(KERN_INFO "early_ioremap(%08lx, %08lx) [%d] => ",
- phys_addr, size, nesting);
+ phys_addr, size, slot);
dump_stack();
}
@@ -604,17 +676,13 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
return NULL;
}
- if (nesting >= FIX_BTMAPS_NESTING) {
- WARN_ON(1);
- return NULL;
- }
- early_ioremap_nested++;
+ prev_size[slot] = size;
/*
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
phys_addr &= PAGE_MASK;
- size = PAGE_ALIGN(last_addr) - phys_addr;
+ size = PAGE_ALIGN(last_addr + 1) - phys_addr;
/*
* Mappings have to fit in the FIX_BTMAP area.
@@ -628,10 +696,10 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
/*
* Ok, go for it..
*/
- idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+ idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
idx = idx0;
while (nrpages > 0) {
- early_set_fixmap(idx, phys_addr);
+ early_set_fixmap(idx, phys_addr, prot);
phys_addr += PAGE_SIZE;
--idx;
--nrpages;
@@ -639,7 +707,20 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
if (early_ioremap_debug)
printk(KERN_CONT "%08lx + %08lx\n", offset, fix_to_virt(idx0));
- return (void *) (offset + fix_to_virt(idx0));
+ prev_map[slot] = (void *) (offset + fix_to_virt(idx0));
+ return prev_map[slot];
+}
+
+/* Remap an IO device */
+void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
+{
+ return __early_ioremap(phys_addr, size, PAGE_KERNEL_IO);
+}
+
+/* Remap memory */
+void __init *early_memremap(unsigned long phys_addr, unsigned long size)
+{
+ return __early_ioremap(phys_addr, size, PAGE_KERNEL);
}
void __init early_iounmap(void *addr, unsigned long size)
@@ -648,15 +729,33 @@ void __init early_iounmap(void *addr, unsigned long size)
unsigned long offset;
unsigned int nrpages;
enum fixed_addresses idx;
- int nesting;
+ int i, slot;
+
+ slot = -1;
+ for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+ if (prev_map[i] == addr) {
+ slot = i;
+ break;
+ }
+ }
- nesting = --early_ioremap_nested;
- if (WARN_ON(nesting < 0))
+ if (slot < 0) {
+ printk(KERN_INFO "early_iounmap(%p, %08lx) not found slot\n",
+ addr, size);
+ WARN_ON(1);
return;
+ }
+
+ if (prev_size[slot] != size) {
+ printk(KERN_INFO "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
+ addr, size, slot, prev_size[slot]);
+ WARN_ON(1);
+ return;
+ }
if (early_ioremap_debug) {
printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr,
- size, nesting);
+ size, slot);
dump_stack();
}
@@ -668,12 +767,13 @@ void __init early_iounmap(void *addr, unsigned long size)
offset = virt_addr & ~PAGE_MASK;
nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
- idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*nesting;
+ idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
while (nrpages > 0) {
early_clear_fixmap(idx);
--idx;
--nrpages;
}
+ prev_map[slot] = 0;
}
void __this_fixmap_does_not_exist(void)
diff --git a/arch/x86/mm/discontig_32.c b/arch/x86/mm/numa_32.c
index 847c164725f..847c164725f 100644
--- a/arch/x86/mm/discontig_32.c
+++ b/arch/x86/mm/numa_32.c
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c
index 1b4763e26ea..51c0a2fc14f 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat_64.c
@@ -138,7 +138,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
return;
}
- if (is_uv_system())
+ if (get_uv_system_type() >= UV_X2APIC)
apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
else
apic_id = pa->apic_id;
diff --git a/arch/x86/oprofile/Makefile b/arch/x86/oprofile/Makefile
index 30f3eb36666..446902b2a6b 100644
--- a/arch/x86/oprofile/Makefile
+++ b/arch/x86/oprofile/Makefile
@@ -7,6 +7,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
-oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \
+oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_amd.o \
op_model_ppro.o op_model_p4.o
oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index 8a5f1614a3d..57f6c908808 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -1,10 +1,11 @@
/**
* @file nmi_int.c
*
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2008 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
+ * @author Robert Richter <robert.richter@amd.com>
*/
#include <linux/init.h>
@@ -439,6 +440,7 @@ int __init op_nmi_init(struct oprofile_operations *ops)
__u8 vendor = boot_cpu_data.x86_vendor;
__u8 family = boot_cpu_data.x86;
char *cpu_type;
+ int ret = 0;
if (!cpu_has_apic)
return -ENODEV;
@@ -451,19 +453,23 @@ int __init op_nmi_init(struct oprofile_operations *ops)
default:
return -ENODEV;
case 6:
- model = &op_athlon_spec;
+ model = &op_amd_spec;
cpu_type = "i386/athlon";
break;
case 0xf:
- model = &op_athlon_spec;
+ model = &op_amd_spec;
/* Actually it could be i386/hammer too, but give
user space an consistent name. */
cpu_type = "x86-64/hammer";
break;
case 0x10:
- model = &op_athlon_spec;
+ model = &op_amd_spec;
cpu_type = "x86-64/family10";
break;
+ case 0x11:
+ model = &op_amd_spec;
+ cpu_type = "x86-64/family11h";
+ break;
}
break;
@@ -490,17 +496,24 @@ int __init op_nmi_init(struct oprofile_operations *ops)
return -ENODEV;
}
- init_sysfs();
#ifdef CONFIG_SMP
register_cpu_notifier(&oprofile_cpu_nb);
#endif
- using_nmi = 1;
+ /* default values, can be overwritten by model */
ops->create_files = nmi_create_files;
ops->setup = nmi_setup;
ops->shutdown = nmi_shutdown;
ops->start = nmi_start;
ops->stop = nmi_stop;
ops->cpu_type = cpu_type;
+
+ if (model->init)
+ ret = model->init(ops);
+ if (ret)
+ return ret;
+
+ init_sysfs();
+ using_nmi = 1;
printk(KERN_INFO "oprofile: using NMI interrupt.\n");
return 0;
}
@@ -513,4 +526,6 @@ void op_nmi_exit(void)
unregister_cpu_notifier(&oprofile_cpu_nb);
#endif
}
+ if (model->exit)
+ model->exit();
}
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
new file mode 100644
index 00000000000..d9faf607b3a
--- /dev/null
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -0,0 +1,543 @@
+/*
+ * @file op_model_amd.c
+ * athlon / K7 / K8 / Family 10h model-specific MSR operations
+ *
+ * @remark Copyright 2002-2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ * @author Robert Richter <robert.richter@amd.com>
+ * @author Barry Kasindorf
+*/
+
+#include <linux/oprofile.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/ptrace.h>
+#include <asm/msr.h>
+#include <asm/nmi.h>
+
+#include "op_x86_model.h"
+#include "op_counter.h"
+
+#define NUM_COUNTERS 4
+#define NUM_CONTROLS 4
+
+#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
+#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
+#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
+#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
+#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
+#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
+#define CTRL_CLEAR_LO(x) (x &= (1<<21))
+#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
+#define CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
+#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
+#define CTRL_SET_UM(val, m) (val |= (m << 8))
+#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
+#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
+#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
+#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
+
+static unsigned long reset_value[NUM_COUNTERS];
+
+#ifdef CONFIG_OPROFILE_IBS
+
+/* IbsFetchCtl bits/masks */
+#define IBS_FETCH_HIGH_VALID_BIT (1UL << 17) /* bit 49 */
+#define IBS_FETCH_HIGH_ENABLE (1UL << 16) /* bit 48 */
+#define IBS_FETCH_LOW_MAX_CNT_MASK 0x0000FFFFUL /* MaxCnt mask */
+
+/*IbsOpCtl bits */
+#define IBS_OP_LOW_VALID_BIT (1ULL<<18) /* bit 18 */
+#define IBS_OP_LOW_ENABLE (1ULL<<17) /* bit 17 */
+
+/* Codes used in cpu_buffer.c */
+/* This produces duplicate code, need to be fixed */
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN 4
+
+/* The function interface needs to be fixed, something like add
+ data. Should then be added to linux/oprofile.h. */
+extern void oprofile_add_ibs_sample(struct pt_regs *const regs,
+ unsigned int * const ibs_sample, u8 code);
+
+struct ibs_fetch_sample {
+ /* MSRC001_1031 IBS Fetch Linear Address Register */
+ unsigned int ibs_fetch_lin_addr_low;
+ unsigned int ibs_fetch_lin_addr_high;
+ /* MSRC001_1030 IBS Fetch Control Register */
+ unsigned int ibs_fetch_ctl_low;
+ unsigned int ibs_fetch_ctl_high;
+ /* MSRC001_1032 IBS Fetch Physical Address Register */
+ unsigned int ibs_fetch_phys_addr_low;
+ unsigned int ibs_fetch_phys_addr_high;
+};
+
+struct ibs_op_sample {
+ /* MSRC001_1034 IBS Op Logical Address Register (IbsRIP) */
+ unsigned int ibs_op_rip_low;
+ unsigned int ibs_op_rip_high;
+ /* MSRC001_1035 IBS Op Data Register */
+ unsigned int ibs_op_data1_low;
+ unsigned int ibs_op_data1_high;
+ /* MSRC001_1036 IBS Op Data 2 Register */
+ unsigned int ibs_op_data2_low;
+ unsigned int ibs_op_data2_high;
+ /* MSRC001_1037 IBS Op Data 3 Register */
+ unsigned int ibs_op_data3_low;
+ unsigned int ibs_op_data3_high;
+ /* MSRC001_1038 IBS DC Linear Address Register (IbsDcLinAd) */
+ unsigned int ibs_dc_linear_low;
+ unsigned int ibs_dc_linear_high;
+ /* MSRC001_1039 IBS DC Physical Address Register (IbsDcPhysAd) */
+ unsigned int ibs_dc_phys_low;
+ unsigned int ibs_dc_phys_high;
+};
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+
+*/
+static void clear_ibs_nmi(void);
+
+static int ibs_allowed; /* AMD Family10h and later */
+
+struct op_ibs_config {
+ unsigned long op_enabled;
+ unsigned long fetch_enabled;
+ unsigned long max_cnt_fetch;
+ unsigned long max_cnt_op;
+ unsigned long rand_en;
+ unsigned long dispatched_ops;
+};
+
+static struct op_ibs_config ibs_config;
+
+#endif
+
+/* functions for op_amd_spec */
+
+static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
+{
+ int i;
+
+ for (i = 0; i < NUM_COUNTERS; i++) {
+ if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
+ msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
+ else
+ msrs->counters[i].addr = 0;
+ }
+
+ for (i = 0; i < NUM_CONTROLS; i++) {
+ if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
+ msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
+ else
+ msrs->controls[i].addr = 0;
+ }
+}
+
+
+static void op_amd_setup_ctrs(struct op_msrs const * const msrs)
+{
+ unsigned int low, high;
+ int i;
+
+ /* clear all counters */
+ for (i = 0 ; i < NUM_CONTROLS; ++i) {
+ if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
+ continue;
+ CTRL_READ(low, high, msrs, i);
+ CTRL_CLEAR_LO(low);
+ CTRL_CLEAR_HI(high);
+ CTRL_WRITE(low, high, msrs, i);
+ }
+
+ /* avoid a false detection of ctr overflows in NMI handler */
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ if (unlikely(!CTR_IS_RESERVED(msrs, i)))
+ continue;
+ CTR_WRITE(1, msrs, i);
+ }
+
+ /* enable active counters */
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
+ reset_value[i] = counter_config[i].count;
+
+ CTR_WRITE(counter_config[i].count, msrs, i);
+
+ CTRL_READ(low, high, msrs, i);
+ CTRL_CLEAR_LO(low);
+ CTRL_CLEAR_HI(high);
+ CTRL_SET_ENABLE(low);
+ CTRL_SET_USR(low, counter_config[i].user);
+ CTRL_SET_KERN(low, counter_config[i].kernel);
+ CTRL_SET_UM(low, counter_config[i].unit_mask);
+ CTRL_SET_EVENT_LOW(low, counter_config[i].event);
+ CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
+ CTRL_SET_HOST_ONLY(high, 0);
+ CTRL_SET_GUEST_ONLY(high, 0);
+
+ CTRL_WRITE(low, high, msrs, i);
+ } else {
+ reset_value[i] = 0;
+ }
+ }
+}
+
+#ifdef CONFIG_OPROFILE_IBS
+
+static inline int
+op_amd_handle_ibs(struct pt_regs * const regs,
+ struct op_msrs const * const msrs)
+{
+ unsigned int low, high;
+ struct ibs_fetch_sample ibs_fetch;
+ struct ibs_op_sample ibs_op;
+
+ if (!ibs_allowed)
+ return 1;
+
+ if (ibs_config.fetch_enabled) {
+ rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+ if (high & IBS_FETCH_HIGH_VALID_BIT) {
+ ibs_fetch.ibs_fetch_ctl_high = high;
+ ibs_fetch.ibs_fetch_ctl_low = low;
+ rdmsr(MSR_AMD64_IBSFETCHLINAD, low, high);
+ ibs_fetch.ibs_fetch_lin_addr_high = high;
+ ibs_fetch.ibs_fetch_lin_addr_low = low;
+ rdmsr(MSR_AMD64_IBSFETCHPHYSAD, low, high);
+ ibs_fetch.ibs_fetch_phys_addr_high = high;
+ ibs_fetch.ibs_fetch_phys_addr_low = low;
+
+ oprofile_add_ibs_sample(regs,
+ (unsigned int *)&ibs_fetch,
+ IBS_FETCH_BEGIN);
+
+ /*reenable the IRQ */
+ rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+ high &= ~IBS_FETCH_HIGH_VALID_BIT;
+ high |= IBS_FETCH_HIGH_ENABLE;
+ low &= IBS_FETCH_LOW_MAX_CNT_MASK;
+ wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+ }
+ }
+
+ if (ibs_config.op_enabled) {
+ rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+ if (low & IBS_OP_LOW_VALID_BIT) {
+ rdmsr(MSR_AMD64_IBSOPRIP, low, high);
+ ibs_op.ibs_op_rip_low = low;
+ ibs_op.ibs_op_rip_high = high;
+ rdmsr(MSR_AMD64_IBSOPDATA, low, high);
+ ibs_op.ibs_op_data1_low = low;
+ ibs_op.ibs_op_data1_high = high;
+ rdmsr(MSR_AMD64_IBSOPDATA2, low, high);
+ ibs_op.ibs_op_data2_low = low;
+ ibs_op.ibs_op_data2_high = high;
+ rdmsr(MSR_AMD64_IBSOPDATA3, low, high);
+ ibs_op.ibs_op_data3_low = low;
+ ibs_op.ibs_op_data3_high = high;
+ rdmsr(MSR_AMD64_IBSDCLINAD, low, high);
+ ibs_op.ibs_dc_linear_low = low;
+ ibs_op.ibs_dc_linear_high = high;
+ rdmsr(MSR_AMD64_IBSDCPHYSAD, low, high);
+ ibs_op.ibs_dc_phys_low = low;
+ ibs_op.ibs_dc_phys_high = high;
+
+ /* reenable the IRQ */
+ oprofile_add_ibs_sample(regs,
+ (unsigned int *)&ibs_op,
+ IBS_OP_BEGIN);
+ rdmsr(MSR_AMD64_IBSOPCTL, low, high);
+ high = 0;
+ low &= ~IBS_OP_LOW_VALID_BIT;
+ low |= IBS_OP_LOW_ENABLE;
+ wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+ }
+ }
+
+ return 1;
+}
+
+#endif
+
+static int op_amd_check_ctrs(struct pt_regs * const regs,
+ struct op_msrs const * const msrs)
+{
+ unsigned int low, high;
+ int i;
+
+ for (i = 0 ; i < NUM_COUNTERS; ++i) {
+ if (!reset_value[i])
+ continue;
+ CTR_READ(low, high, msrs, i);
+ if (CTR_OVERFLOWED(low)) {
+ oprofile_add_sample(regs, i);
+ CTR_WRITE(reset_value[i], msrs, i);
+ }
+ }
+
+#ifdef CONFIG_OPROFILE_IBS
+ op_amd_handle_ibs(regs, msrs);
+#endif
+
+ /* See op_model_ppro.c */
+ return 1;
+}
+
+static void op_amd_start(struct op_msrs const * const msrs)
+{
+ unsigned int low, high;
+ int i;
+ for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+ if (reset_value[i]) {
+ CTRL_READ(low, high, msrs, i);
+ CTRL_SET_ACTIVE(low);
+ CTRL_WRITE(low, high, msrs, i);
+ }
+ }
+
+#ifdef CONFIG_OPROFILE_IBS
+ if (ibs_allowed && ibs_config.fetch_enabled) {
+ low = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF;
+ high = IBS_FETCH_HIGH_ENABLE;
+ wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+ }
+
+ if (ibs_allowed && ibs_config.op_enabled) {
+ low = ((ibs_config.max_cnt_op >> 4) & 0xFFFF) + IBS_OP_LOW_ENABLE;
+ high = 0;
+ wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+ }
+#endif
+}
+
+
+static void op_amd_stop(struct op_msrs const * const msrs)
+{
+ unsigned int low, high;
+ int i;
+
+ /* Subtle: stop on all counters to avoid race with
+ * setting our pm callback */
+ for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+ if (!reset_value[i])
+ continue;
+ CTRL_READ(low, high, msrs, i);
+ CTRL_SET_INACTIVE(low);
+ CTRL_WRITE(low, high, msrs, i);
+ }
+
+#ifdef CONFIG_OPROFILE_IBS
+ if (ibs_allowed && ibs_config.fetch_enabled) {
+ low = 0; /* clear max count and enable */
+ high = 0;
+ wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
+ }
+
+ if (ibs_allowed && ibs_config.op_enabled) {
+ low = 0; /* clear max count and enable */
+ high = 0;
+ wrmsr(MSR_AMD64_IBSOPCTL, low, high);
+ }
+#endif
+}
+
+static void op_amd_shutdown(struct op_msrs const * const msrs)
+{
+ int i;
+
+ for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+ if (CTR_IS_RESERVED(msrs, i))
+ release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+ }
+ for (i = 0 ; i < NUM_CONTROLS ; ++i) {
+ if (CTRL_IS_RESERVED(msrs, i))
+ release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+ }
+}
+
+#ifndef CONFIG_OPROFILE_IBS
+
+/* no IBS support */
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+ return 0;
+}
+
+static void op_amd_exit(void) {}
+
+#else
+
+static u8 ibs_eilvt_off;
+
+static inline void apic_init_ibs_nmi_per_cpu(void *arg)
+{
+ ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
+}
+
+static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
+{
+ setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
+}
+
+static int pfm_amd64_setup_eilvt(void)
+{
+#define IBSCTL_LVTOFFSETVAL (1 << 8)
+#define IBSCTL 0x1cc
+ struct pci_dev *cpu_cfg;
+ int nodes;
+ u32 value = 0;
+
+ /* per CPU setup */
+ on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
+
+ nodes = 0;
+ cpu_cfg = NULL;
+ do {
+ cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_10H_NB_MISC,
+ cpu_cfg);
+ if (!cpu_cfg)
+ break;
+ ++nodes;
+ pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
+ | IBSCTL_LVTOFFSETVAL);
+ pci_read_config_dword(cpu_cfg, IBSCTL, &value);
+ if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
+ printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
+ "IBSCTL = 0x%08x", value);
+ return 1;
+ }
+ } while (1);
+
+ if (!nodes) {
+ printk(KERN_DEBUG "No CPU node configured for IBS");
+ return 1;
+ }
+
+#ifdef CONFIG_NUMA
+ /* Sanity check */
+ /* Works only for 64bit with proper numa implementation. */
+ if (nodes != num_possible_nodes()) {
+ printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
+ "found: %d, expected %d",
+ nodes, num_possible_nodes());
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * initialize the APIC for the IBS interrupts
+ * if available (AMD Family10h rev B0 and later)
+ */
+static void setup_ibs(void)
+{
+ ibs_allowed = boot_cpu_has(X86_FEATURE_IBS);
+
+ if (!ibs_allowed)
+ return;
+
+ if (pfm_amd64_setup_eilvt()) {
+ ibs_allowed = 0;
+ return;
+ }
+
+ printk(KERN_INFO "oprofile: AMD IBS detected\n");
+}
+
+
+/*
+ * unitialize the APIC for the IBS interrupts if needed on AMD Family10h
+ * rev B0 and later */
+static void clear_ibs_nmi(void)
+{
+ if (ibs_allowed)
+ on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}
+
+static int (*create_arch_files)(struct super_block * sb, struct dentry * root);
+
+static int setup_ibs_files(struct super_block * sb, struct dentry * root)
+{
+ char buf[12];
+ struct dentry *dir;
+ int ret = 0;
+
+ /* architecture specific files */
+ if (create_arch_files)
+ ret = create_arch_files(sb, root);
+
+ if (ret)
+ return ret;
+
+ if (!ibs_allowed)
+ return ret;
+
+ /* model specific files */
+
+ /* setup some reasonable defaults */
+ ibs_config.max_cnt_fetch = 250000;
+ ibs_config.fetch_enabled = 0;
+ ibs_config.max_cnt_op = 250000;
+ ibs_config.op_enabled = 0;
+ ibs_config.dispatched_ops = 1;
+ snprintf(buf, sizeof(buf), "ibs_fetch");
+ dir = oprofilefs_mkdir(sb, root, buf);
+ oprofilefs_create_ulong(sb, dir, "rand_enable",
+ &ibs_config.rand_en);
+ oprofilefs_create_ulong(sb, dir, "enable",
+ &ibs_config.fetch_enabled);
+ oprofilefs_create_ulong(sb, dir, "max_count",
+ &ibs_config.max_cnt_fetch);
+ snprintf(buf, sizeof(buf), "ibs_uops");
+ dir = oprofilefs_mkdir(sb, root, buf);
+ oprofilefs_create_ulong(sb, dir, "enable",
+ &ibs_config.op_enabled);
+ oprofilefs_create_ulong(sb, dir, "max_count",
+ &ibs_config.max_cnt_op);
+ oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+ &ibs_config.dispatched_ops);
+
+ return 0;
+}
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+ setup_ibs();
+ create_arch_files = ops->create_files;
+ ops->create_files = setup_ibs_files;
+ return 0;
+}
+
+static void op_amd_exit(void)
+{
+ clear_ibs_nmi();
+}
+
+#endif
+
+struct op_x86_model_spec const op_amd_spec = {
+ .init = op_amd_init,
+ .exit = op_amd_exit,
+ .num_counters = NUM_COUNTERS,
+ .num_controls = NUM_CONTROLS,
+ .fill_in_addresses = &op_amd_fill_in_addresses,
+ .setup_ctrs = &op_amd_setup_ctrs,
+ .check_ctrs = &op_amd_check_ctrs,
+ .start = &op_amd_start,
+ .stop = &op_amd_stop,
+ .shutdown = &op_amd_shutdown
+};
diff --git a/arch/x86/oprofile/op_model_athlon.c b/arch/x86/oprofile/op_model_athlon.c
deleted file mode 100644
index 3d534879a9d..00000000000
--- a/arch/x86/oprofile/op_model_athlon.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * @file op_model_athlon.h
- * athlon / K7 / K8 / Family 10h model-specific MSR operations
- *
- * @remark Copyright 2002 OProfile authors
- * @remark Read the file COPYING
- *
- * @author John Levon
- * @author Philippe Elie
- * @author Graydon Hoare
- */
-
-#include <linux/oprofile.h>
-#include <asm/ptrace.h>
-#include <asm/msr.h>
-#include <asm/nmi.h>
-
-#include "op_x86_model.h"
-#include "op_counter.h"
-
-#define NUM_COUNTERS 4
-#define NUM_CONTROLS 4
-
-#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
-#define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters[(c)].addr, (l), (h)); } while (0)
-#define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1); } while (0)
-#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
-
-#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
-#define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls[(c)].addr, (l), (h)); } while (0)
-#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
-#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
-#define CTRL_CLEAR_LO(x) (x &= (1<<21))
-#define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0)
-#define CTRL_SET_ENABLE(val) (val |= 1<<20)
-#define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
-#define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
-#define CTRL_SET_UM(val, m) (val |= (m << 8))
-#define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff))
-#define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf))
-#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 1) << 9))
-#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 1) << 8))
-
-static unsigned long reset_value[NUM_COUNTERS];
-
-static void athlon_fill_in_addresses(struct op_msrs * const msrs)
-{
- int i;
-
- for (i = 0; i < NUM_COUNTERS; i++) {
- if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
- msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
- else
- msrs->counters[i].addr = 0;
- }
-
- for (i = 0; i < NUM_CONTROLS; i++) {
- if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
- msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
- else
- msrs->controls[i].addr = 0;
- }
-}
-
-
-static void athlon_setup_ctrs(struct op_msrs const * const msrs)
-{
- unsigned int low, high;
- int i;
-
- /* clear all counters */
- for (i = 0 ; i < NUM_CONTROLS; ++i) {
- if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
- continue;
- CTRL_READ(low, high, msrs, i);
- CTRL_CLEAR_LO(low);
- CTRL_CLEAR_HI(high);
- CTRL_WRITE(low, high, msrs, i);
- }
-
- /* avoid a false detection of ctr overflows in NMI handler */
- for (i = 0; i < NUM_COUNTERS; ++i) {
- if (unlikely(!CTR_IS_RESERVED(msrs, i)))
- continue;
- CTR_WRITE(1, msrs, i);
- }
-
- /* enable active counters */
- for (i = 0; i < NUM_COUNTERS; ++i) {
- if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) {
- reset_value[i] = counter_config[i].count;
-
- CTR_WRITE(counter_config[i].count, msrs, i);
-
- CTRL_READ(low, high, msrs, i);
- CTRL_CLEAR_LO(low);
- CTRL_CLEAR_HI(high);
- CTRL_SET_ENABLE(low);
- CTRL_SET_USR(low, counter_config[i].user);
- CTRL_SET_KERN(low, counter_config[i].kernel);
- CTRL_SET_UM(low, counter_config[i].unit_mask);
- CTRL_SET_EVENT_LOW(low, counter_config[i].event);
- CTRL_SET_EVENT_HIGH(high, counter_config[i].event);
- CTRL_SET_HOST_ONLY(high, 0);
- CTRL_SET_GUEST_ONLY(high, 0);
-
- CTRL_WRITE(low, high, msrs, i);
- } else {
- reset_value[i] = 0;
- }
- }
-}
-
-
-static int athlon_check_ctrs(struct pt_regs * const regs,
- struct op_msrs const * const msrs)
-{
- unsigned int low, high;
- int i;
-
- for (i = 0 ; i < NUM_COUNTERS; ++i) {
- if (!reset_value[i])
- continue;
- CTR_READ(low, high, msrs, i);
- if (CTR_OVERFLOWED(low)) {
- oprofile_add_sample(regs, i);
- CTR_WRITE(reset_value[i], msrs, i);
- }
- }
-
- /* See op_model_ppro.c */
- return 1;
-}
-
-
-static void athlon_start(struct op_msrs const * const msrs)
-{
- unsigned int low, high;
- int i;
- for (i = 0 ; i < NUM_COUNTERS ; ++i) {
- if (reset_value[i]) {
- CTRL_READ(low, high, msrs, i);
- CTRL_SET_ACTIVE(low);
- CTRL_WRITE(low, high, msrs, i);
- }
- }
-}
-
-
-static void athlon_stop(struct op_msrs const * const msrs)
-{
- unsigned int low, high;
- int i;
-
- /* Subtle: stop on all counters to avoid race with
- * setting our pm callback */
- for (i = 0 ; i < NUM_COUNTERS ; ++i) {
- if (!reset_value[i])
- continue;
- CTRL_READ(low, high, msrs, i);
- CTRL_SET_INACTIVE(low);
- CTRL_WRITE(low, high, msrs, i);
- }
-}
-
-static void athlon_shutdown(struct op_msrs const * const msrs)
-{
- int i;
-
- for (i = 0 ; i < NUM_COUNTERS ; ++i) {
- if (CTR_IS_RESERVED(msrs, i))
- release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
- }
- for (i = 0 ; i < NUM_CONTROLS ; ++i) {
- if (CTRL_IS_RESERVED(msrs, i))
- release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
- }
-}
-
-struct op_x86_model_spec const op_athlon_spec = {
- .num_counters = NUM_COUNTERS,
- .num_controls = NUM_CONTROLS,
- .fill_in_addresses = &athlon_fill_in_addresses,
- .setup_ctrs = &athlon_setup_ctrs,
- .check_ctrs = &athlon_check_ctrs,
- .start = &athlon_start,
- .stop = &athlon_stop,
- .shutdown = &athlon_shutdown
-};
diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h
index 45b605fa71d..05a0261ba0c 100644
--- a/arch/x86/oprofile/op_x86_model.h
+++ b/arch/x86/oprofile/op_x86_model.h
@@ -32,6 +32,8 @@ struct pt_regs;
* various x86 CPU models' perfctr support.
*/
struct op_x86_model_spec {
+ int (*init)(struct oprofile_operations *ops);
+ void (*exit)(void);
unsigned int const num_counters;
unsigned int const num_controls;
void (*fill_in_addresses)(struct op_msrs * const msrs);
@@ -46,6 +48,6 @@ struct op_x86_model_spec {
extern struct op_x86_model_spec const op_ppro_spec;
extern struct op_x86_model_spec const op_p4_spec;
extern struct op_x86_model_spec const op_p4_ht2_spec;
-extern struct op_x86_model_spec const op_athlon_spec;
+extern struct op_x86_model_spec const op_amd_spec;
#endif /* OP_X86_MODEL_H */
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 4bdaa590375..3c27a809393 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -511,3 +511,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size);
+
+/*
+ * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from
+ * confusing the PCI engine:
+ */
+static void sb600_disable_hpet_bar(struct pci_dev *dev)
+{
+ u8 val;
+
+ /*
+ * The SB600 and SB700 both share the same device
+ * ID, but the PM register 0x55 does something different
+ * for the SB700, so make sure we are dealing with the
+ * SB600 before touching the bit:
+ */
+
+ pci_read_config_byte(dev, 0x08, &val);
+
+ if (val < 0x2F) {
+ outb(0x55, 0xCD6);
+ val = inb(0xCD7);
+
+ /* Set bit 7 in PM register 0x55 */
+ outb(0x55, 0xCD6);
+ outb(val | 0x80, 0xCD7);
+ }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 3815e425f47..87b9ab16642 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -26,5 +26,13 @@ config XEN_MAX_DOMAIN_MEMORY
config XEN_SAVE_RESTORE
bool
- depends on PM
- default y \ No newline at end of file
+ depends on XEN && PM
+ default y
+
+config XEN_DEBUG_FS
+ bool "Enable Xen debug and tuning parameters in debugfs"
+ depends on XEN && DEBUG_FS
+ default n
+ help
+ Enable statistics output and various tuning options in debugfs.
+ Enabling this option may incur a significant performance overhead.
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 59c1e539aed..313947940a1 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -1,4 +1,12 @@
-obj-y := enlighten.o setup.o multicalls.o mmu.o \
+ifdef CONFIG_FTRACE
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_spinlock.o = -pg
+CFLAGS_REMOVE_time.o = -pg
+CFLAGS_REMOVE_irq.o = -pg
+endif
+
+obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
time.o xen-asm_$(BITS).o grant-table.o suspend.o
-obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_SMP) += smp.o spinlock.o
+obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o \ No newline at end of file
diff --git a/arch/x86/xen/debugfs.c b/arch/x86/xen/debugfs.c
new file mode 100644
index 00000000000..b53225d2cac
--- /dev/null
+++ b/arch/x86/xen/debugfs.c
@@ -0,0 +1,123 @@
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "debugfs.h"
+
+static struct dentry *d_xen_debug;
+
+struct dentry * __init xen_init_debugfs(void)
+{
+ if (!d_xen_debug) {
+ d_xen_debug = debugfs_create_dir("xen", NULL);
+
+ if (!d_xen_debug)
+ pr_warning("Could not create 'xen' debugfs directory\n");
+ }
+
+ return d_xen_debug;
+}
+
+struct array_data
+{
+ void *array;
+ unsigned elements;
+};
+
+static int u32_array_open(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return nonseekable_open(inode, file);
+}
+
+static size_t format_array(char *buf, size_t bufsize, const char *fmt,
+ u32 *array, unsigned array_size)
+{
+ size_t ret = 0;
+ unsigned i;
+
+ for(i = 0; i < array_size; i++) {
+ size_t len;
+
+ len = snprintf(buf, bufsize, fmt, array[i]);
+ len++; /* ' ' or '\n' */
+ ret += len;
+
+ if (buf) {
+ buf += len;
+ bufsize -= len;
+ buf[-1] = (i == array_size-1) ? '\n' : ' ';
+ }
+ }
+
+ ret++; /* \0 */
+ if (buf)
+ *buf = '\0';
+
+ return ret;
+}
+
+static char *format_array_alloc(const char *fmt, u32 *array, unsigned array_size)
+{
+ size_t len = format_array(NULL, 0, fmt, array, array_size);
+ char *ret;
+
+ ret = kmalloc(len, GFP_KERNEL);
+ if (ret == NULL)
+ return NULL;
+
+ format_array(ret, len, fmt, array, array_size);
+ return ret;
+}
+
+static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct array_data *data = inode->i_private;
+ size_t size;
+
+ if (*ppos == 0) {
+ if (file->private_data) {
+ kfree(file->private_data);
+ file->private_data = NULL;
+ }
+
+ file->private_data = format_array_alloc("%u", data->array, data->elements);
+ }
+
+ size = 0;
+ if (file->private_data)
+ size = strlen(file->private_data);
+
+ return simple_read_from_buffer(buf, len, ppos, file->private_data, size);
+}
+
+static int xen_array_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static struct file_operations u32_array_fops = {
+ .owner = THIS_MODULE,
+ .open = u32_array_open,
+ .release= xen_array_release,
+ .read = u32_array_read,
+};
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+ struct dentry *parent,
+ u32 *array, unsigned elements)
+{
+ struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+ if (data == NULL)
+ return NULL;
+
+ data->array = array;
+ data->elements = elements;
+
+ return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
+}
diff --git a/arch/x86/xen/debugfs.h b/arch/x86/xen/debugfs.h
new file mode 100644
index 00000000000..e2813208483
--- /dev/null
+++ b/arch/x86/xen/debugfs.h
@@ -0,0 +1,10 @@
+#ifndef _XEN_DEBUGFS_H
+#define _XEN_DEBUGFS_H
+
+struct dentry * __init xen_init_debugfs(void);
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+ struct dentry *parent,
+ u32 *array, unsigned elements);
+
+#endif /* _XEN_DEBUGFS_H */
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index a27d562a974..0013a729b41 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -30,7 +30,6 @@
#include <xen/interface/xen.h>
#include <xen/interface/physdev.h>
#include <xen/interface/vcpu.h>
-#include <xen/interface/sched.h>
#include <xen/features.h>
#include <xen/page.h>
#include <xen/hvc-console.h>
@@ -58,6 +57,9 @@ EXPORT_SYMBOL_GPL(hypercall_page);
DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+EXPORT_SYMBOL_GPL(xen_domain_type);
+
/*
* Identity map, in addition to plain kernel map. This needs to be
* large enough to allocate page table pages to allocate the rest.
@@ -111,7 +113,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
*
* 0: not available, 1: available
*/
-static int have_vcpu_info_placement = 1;
+static int have_vcpu_info_placement =
+#ifdef CONFIG_X86_32
+ 1
+#else
+ 0
+#endif
+ ;
+
static void xen_vcpu_setup(int cpu)
{
@@ -227,103 +236,68 @@ static unsigned long xen_get_debugreg(int reg)
return HYPERVISOR_get_debugreg(reg);
}
-static unsigned long xen_save_fl(void)
+static void xen_leave_lazy(void)
{
- struct vcpu_info *vcpu;
- unsigned long flags;
-
- vcpu = x86_read_percpu(xen_vcpu);
-
- /* flag has opposite sense of mask */
- flags = !vcpu->evtchn_upcall_mask;
-
- /* convert to IF type flag
- -0 -> 0x00000000
- -1 -> 0xffffffff
- */
- return (-flags) & X86_EFLAGS_IF;
+ paravirt_leave_lazy(paravirt_get_lazy_mode());
+ xen_mc_flush();
}
-static void xen_restore_fl(unsigned long flags)
+static unsigned long xen_store_tr(void)
{
- struct vcpu_info *vcpu;
-
- /* convert from IF type flag */
- flags = !(flags & X86_EFLAGS_IF);
-
- /* There's a one instruction preempt window here. We need to
- make sure we're don't switch CPUs between getting the vcpu
- pointer and updating the mask. */
- preempt_disable();
- vcpu = x86_read_percpu(xen_vcpu);
- vcpu->evtchn_upcall_mask = flags;
- preempt_enable_no_resched();
-
- /* Doesn't matter if we get preempted here, because any
- pending event will get dealt with anyway. */
-
- if (flags == 0) {
- preempt_check_resched();
- barrier(); /* unmask then check (avoid races) */
- if (unlikely(vcpu->evtchn_upcall_pending))
- force_evtchn_callback();
- }
+ return 0;
}
-static void xen_irq_disable(void)
+/*
+ * Set the page permissions for a particular virtual address. If the
+ * address is a vmalloc mapping (or other non-linear mapping), then
+ * find the linear mapping of the page and also set its protections to
+ * match.
+ */
+static void set_aliased_prot(void *v, pgprot_t prot)
{
- /* There's a one instruction preempt window here. We need to
- make sure we're don't switch CPUs between getting the vcpu
- pointer and updating the mask. */
- preempt_disable();
- x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
- preempt_enable_no_resched();
-}
+ int level;
+ pte_t *ptep;
+ pte_t pte;
+ unsigned long pfn;
+ struct page *page;
-static void xen_irq_enable(void)
-{
- struct vcpu_info *vcpu;
+ ptep = lookup_address((unsigned long)v, &level);
+ BUG_ON(ptep == NULL);
- /* We don't need to worry about being preempted here, since
- either a) interrupts are disabled, so no preemption, or b)
- the caller is confused and is trying to re-enable interrupts
- on an indeterminate processor. */
+ pfn = pte_pfn(*ptep);
+ page = pfn_to_page(pfn);
- vcpu = x86_read_percpu(xen_vcpu);
- vcpu->evtchn_upcall_mask = 0;
+ pte = pfn_pte(pfn, prot);
- /* Doesn't matter if we get preempted here, because any
- pending event will get dealt with anyway. */
+ if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
+ BUG();
- barrier(); /* unmask then check (avoid races) */
- if (unlikely(vcpu->evtchn_upcall_pending))
- force_evtchn_callback();
-}
+ if (!PageHighMem(page)) {
+ void *av = __va(PFN_PHYS(pfn));
-static void xen_safe_halt(void)
-{
- /* Blocking includes an implicit local_irq_enable(). */
- if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
- BUG();
+ if (av != v)
+ if (HYPERVISOR_update_va_mapping((unsigned long)av, pte, 0))
+ BUG();
+ } else
+ kmap_flush_unused();
}
-static void xen_halt(void)
+static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
{
- if (irqs_disabled())
- HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
- else
- xen_safe_halt();
-}
+ const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+ int i;
-static void xen_leave_lazy(void)
-{
- paravirt_leave_lazy(paravirt_get_lazy_mode());
- xen_mc_flush();
+ for(i = 0; i < entries; i += entries_per_page)
+ set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
}
-static unsigned long xen_store_tr(void)
+static void xen_free_ldt(struct desc_struct *ldt, unsigned entries)
{
- return 0;
+ const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+ int i;
+
+ for(i = 0; i < entries; i += entries_per_page)
+ set_aliased_prot(ldt + i, PAGE_KERNEL);
}
static void xen_set_ldt(const void *addr, unsigned entries)
@@ -426,8 +400,7 @@ static void xen_load_gs_index(unsigned int idx)
static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
const void *ptr)
{
- unsigned long lp = (unsigned long)&dt[entrynum];
- xmaddr_t mach_lp = virt_to_machine(lp);
+ xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]);
u64 entry = *(u64 *)ptr;
preempt_disable();
@@ -560,7 +533,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
}
static void xen_load_sp0(struct tss_struct *tss,
- struct thread_struct *thread)
+ struct thread_struct *thread)
{
struct multicall_space mcs = xen_mc_entry(0);
MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0);
@@ -835,6 +808,19 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
ret = -EFAULT;
break;
#endif
+
+ case MSR_STAR:
+ case MSR_CSTAR:
+ case MSR_LSTAR:
+ case MSR_SYSCALL_MASK:
+ case MSR_IA32_SYSENTER_CS:
+ case MSR_IA32_SYSENTER_ESP:
+ case MSR_IA32_SYSENTER_EIP:
+ /* Fast syscall setup is all done in hypercalls, so
+ these are all ignored. Stub them out here to stop
+ Xen console noise. */
+ break;
+
default:
ret = native_write_msr_safe(msr, low, high);
}
@@ -878,8 +864,8 @@ static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned l
SetPagePinned(page);
if (!PageHighMem(page)) {
- make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
- if (level == PT_PTE)
+ make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
+ if (level == PT_PTE && USE_SPLIT_PTLOCKS)
pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
} else
/* make sure there are no stray mappings of
@@ -947,7 +933,7 @@ static void xen_release_ptpage(unsigned long pfn, unsigned level)
if (PagePinned(page)) {
if (!PageHighMem(page)) {
- if (level == PT_PTE)
+ if (level == PT_PTE && USE_SPLIT_PTLOCKS)
pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
}
@@ -994,6 +980,7 @@ static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
}
#endif
+#ifdef CONFIG_X86_32
static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
{
/* If there's an existing pte, then don't allow _PAGE_RW to be set */
@@ -1012,6 +999,7 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
xen_set_pte(ptep, pte);
}
+#endif
static __init void xen_pagetable_setup_start(pgd_t *base)
{
@@ -1078,7 +1066,6 @@ void xen_setup_vcpu_info_placement(void)
/* xen_vcpu_setup managed to place the vcpu_info within the
percpu area for all cpus, so make use of it */
-#ifdef CONFIG_X86_32
if (have_vcpu_info_placement) {
printk(KERN_INFO "Xen: using vcpu_info placement\n");
@@ -1088,7 +1075,6 @@ void xen_setup_vcpu_info_placement(void)
pv_irq_ops.irq_enable = xen_irq_enable_direct;
pv_mmu_ops.read_cr2 = xen_read_cr2_direct;
}
-#endif
}
static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
@@ -1109,12 +1095,10 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
goto patch_site
switch (type) {
-#ifdef CONFIG_X86_32
SITE(pv_irq_ops, irq_enable);
SITE(pv_irq_ops, irq_disable);
SITE(pv_irq_ops, save_fl);
SITE(pv_irq_ops, restore_fl);
-#endif /* CONFIG_X86_32 */
#undef SITE
patch_site:
@@ -1252,6 +1236,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
.load_gs_index = xen_load_gs_index,
#endif
+ .alloc_ldt = xen_alloc_ldt,
+ .free_ldt = xen_free_ldt,
+
.store_gdt = native_store_gdt,
.store_idt = native_store_idt,
.store_tr = xen_store_tr,
@@ -1273,36 +1260,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
},
};
-static void __init __xen_init_IRQ(void)
-{
-#ifdef CONFIG_X86_64
- int i;
-
- /* Create identity vector->irq map */
- for(i = 0; i < NR_VECTORS; i++) {
- int cpu;
-
- for_each_possible_cpu(cpu)
- per_cpu(vector_irq, cpu)[i] = i;
- }
-#endif /* CONFIG_X86_64 */
-
- xen_init_IRQ();
-}
-
-static const struct pv_irq_ops xen_irq_ops __initdata = {
- .init_IRQ = __xen_init_IRQ,
- .save_fl = xen_save_fl,
- .restore_fl = xen_restore_fl,
- .irq_disable = xen_irq_disable,
- .irq_enable = xen_irq_enable,
- .safe_halt = xen_safe_halt,
- .halt = xen_halt,
-#ifdef CONFIG_X86_64
- .adjust_exception_frame = xen_adjust_exception_frame,
-#endif
-};
-
static const struct pv_apic_ops xen_apic_ops __initdata = {
#ifdef CONFIG_X86_LOCAL_APIC
.setup_boot_clock = paravirt_nop,
@@ -1443,7 +1400,7 @@ static void __init xen_reserve_top(void)
if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
top = pp.virt_start;
- reserve_top_address(-top + 2 * PAGE_SIZE);
+ reserve_top_address(-top);
#endif /* CONFIG_X86_32 */
}
@@ -1477,48 +1434,11 @@ static void *m2v(phys_addr_t maddr)
return __ka(m2p(maddr));
}
-#ifdef CONFIG_X86_64
-static void walk(pgd_t *pgd, unsigned long addr)
-{
- unsigned l4idx = pgd_index(addr);
- unsigned l3idx = pud_index(addr);
- unsigned l2idx = pmd_index(addr);
- unsigned l1idx = pte_index(addr);
- pgd_t l4;
- pud_t l3;
- pmd_t l2;
- pte_t l1;
-
- xen_raw_printk("walk %p, %lx -> %d %d %d %d\n",
- pgd, addr, l4idx, l3idx, l2idx, l1idx);
-
- l4 = pgd[l4idx];
- xen_raw_printk(" l4: %016lx\n", l4.pgd);
- xen_raw_printk(" %016lx\n", pgd_val(l4));
-
- l3 = ((pud_t *)(m2v(l4.pgd)))[l3idx];
- xen_raw_printk(" l3: %016lx\n", l3.pud);
- xen_raw_printk(" %016lx\n", pud_val(l3));
-
- l2 = ((pmd_t *)(m2v(l3.pud)))[l2idx];
- xen_raw_printk(" l2: %016lx\n", l2.pmd);
- xen_raw_printk(" %016lx\n", pmd_val(l2));
-
- l1 = ((pte_t *)(m2v(l2.pmd)))[l1idx];
- xen_raw_printk(" l1: %016lx\n", l1.pte);
- xen_raw_printk(" %016lx\n", pte_val(l1));
-}
-#endif
-
static void set_page_prot(void *addr, pgprot_t prot)
{
unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
pte_t pte = pfn_pte(pfn, prot);
- xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016llx pte=%016llx\n",
- addr, pfn, get_phys_to_machine(pfn),
- pgprot_val(prot), pte.pte);
-
if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
BUG();
}
@@ -1694,6 +1614,8 @@ asmlinkage void __init xen_start_kernel(void)
if (!xen_start_info)
return;
+ xen_domain_type = XEN_PV_DOMAIN;
+
BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0);
xen_setup_features();
@@ -1703,10 +1625,11 @@ asmlinkage void __init xen_start_kernel(void)
pv_init_ops = xen_init_ops;
pv_time_ops = xen_time_ops;
pv_cpu_ops = xen_cpu_ops;
- pv_irq_ops = xen_irq_ops;
pv_apic_ops = xen_apic_ops;
pv_mmu_ops = xen_mmu_ops;
+ xen_init_irq_ops();
+
#ifdef CONFIG_X86_LOCAL_APIC
/*
* set up the basic apic ops.
@@ -1737,7 +1660,7 @@ asmlinkage void __init xen_start_kernel(void)
/* Prevent unwanted bits from being set in PTEs. */
__supported_pte_mask &= ~_PAGE_GLOBAL;
- if (!is_initial_xendomain())
+ if (!xen_initial_domain())
__supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
/* Don't do the full vcpu_info placement stuff until we have a
@@ -1772,7 +1695,7 @@ asmlinkage void __init xen_start_kernel(void)
boot_params.hdr.ramdisk_size = xen_start_info->mod_len;
boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line);
- if (!is_initial_xendomain()) {
+ if (!xen_initial_domain()) {
add_preferred_console("xenboot", 0, NULL);
add_preferred_console("tty", 0, NULL);
add_preferred_console("hvc", 0, NULL);
@@ -1780,15 +1703,6 @@ asmlinkage void __init xen_start_kernel(void)
xen_raw_console_write("about to get started...\n");
-#if 0
- xen_raw_printk("&boot_params=%p __pa(&boot_params)=%lx __va(__pa(&boot_params))=%lx\n",
- &boot_params, __pa_symbol(&boot_params),
- __va(__pa_symbol(&boot_params)));
-
- walk(pgd, &boot_params);
- walk(pgd, __va(__pa(&boot_params)));
-#endif
-
/* Start the world */
#ifdef CONFIG_X86_32
i386_start_kernel();
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
new file mode 100644
index 00000000000..28b85ab8422
--- /dev/null
+++ b/arch/x86/xen/irq.c
@@ -0,0 +1,143 @@
+#include <linux/hardirq.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include "xen-ops.h"
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void xen_force_evtchn_callback(void)
+{
+ (void)HYPERVISOR_xen_version(0, NULL);
+}
+
+static void __init __xen_init_IRQ(void)
+{
+#ifdef CONFIG_X86_64
+ int i;
+
+ /* Create identity vector->irq map */
+ for(i = 0; i < NR_VECTORS; i++) {
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ per_cpu(vector_irq, cpu)[i] = i;
+ }
+#endif /* CONFIG_X86_64 */
+
+ xen_init_IRQ();
+}
+
+static unsigned long xen_save_fl(void)
+{
+ struct vcpu_info *vcpu;
+ unsigned long flags;
+
+ vcpu = x86_read_percpu(xen_vcpu);
+
+ /* flag has opposite sense of mask */
+ flags = !vcpu->evtchn_upcall_mask;
+
+ /* convert to IF type flag
+ -0 -> 0x00000000
+ -1 -> 0xffffffff
+ */
+ return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+ struct vcpu_info *vcpu;
+
+ /* convert from IF type flag */
+ flags = !(flags & X86_EFLAGS_IF);
+
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = flags;
+ preempt_enable_no_resched();
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ if (flags == 0) {
+ preempt_check_resched();
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ xen_force_evtchn_callback();
+ }
+}
+
+static void xen_irq_disable(void)
+{
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+ preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+ struct vcpu_info *vcpu;
+
+ /* We don't need to worry about being preempted here, since
+ either a) interrupts are disabled, so no preemption, or b)
+ the caller is confused and is trying to re-enable interrupts
+ on an indeterminate processor. */
+
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = 0;
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ xen_force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+ /* Blocking includes an implicit local_irq_enable(). */
+ if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
+ BUG();
+}
+
+static void xen_halt(void)
+{
+ if (irqs_disabled())
+ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+ else
+ xen_safe_halt();
+}
+
+static const struct pv_irq_ops xen_irq_ops __initdata = {
+ .init_IRQ = __xen_init_IRQ,
+ .save_fl = xen_save_fl,
+ .restore_fl = xen_restore_fl,
+ .irq_disable = xen_irq_disable,
+ .irq_enable = xen_irq_enable,
+ .safe_halt = xen_safe_halt,
+ .halt = xen_halt,
+#ifdef CONFIG_X86_64
+ .adjust_exception_frame = xen_adjust_exception_frame,
+#endif
+};
+
+void __init xen_init_irq_ops()
+{
+ pv_irq_ops = xen_irq_ops;
+}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index aa37469da69..ae173f6edd8 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -40,6 +40,7 @@
*/
#include <linux/sched.h>
#include <linux/highmem.h>
+#include <linux/debugfs.h>
#include <linux/bug.h>
#include <asm/pgtable.h>
@@ -57,6 +58,61 @@
#include "multicalls.h"
#include "mmu.h"
+#include "debugfs.h"
+
+#define MMU_UPDATE_HISTO 30
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct {
+ u32 pgd_update;
+ u32 pgd_update_pinned;
+ u32 pgd_update_batched;
+
+ u32 pud_update;
+ u32 pud_update_pinned;
+ u32 pud_update_batched;
+
+ u32 pmd_update;
+ u32 pmd_update_pinned;
+ u32 pmd_update_batched;
+
+ u32 pte_update;
+ u32 pte_update_pinned;
+ u32 pte_update_batched;
+
+ u32 mmu_update;
+ u32 mmu_update_extended;
+ u32 mmu_update_histo[MMU_UPDATE_HISTO];
+
+ u32 prot_commit;
+ u32 prot_commit_batched;
+
+ u32 set_pte_at;
+ u32 set_pte_at_batched;
+ u32 set_pte_at_pinned;
+ u32 set_pte_at_current;
+ u32 set_pte_at_kernel;
+} mmu_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+ if (unlikely(zero_stats)) {
+ memset(&mmu_stats, 0, sizeof(mmu_stats));
+ zero_stats = 0;
+ }
+}
+
+#define ADD_STATS(elem, val) \
+ do { check_zero(); mmu_stats.elem += (val); } while(0)
+
+#else /* !CONFIG_XEN_DEBUG_FS */
+
+#define ADD_STATS(elem, val) do { (void)(val); } while(0)
+
+#endif /* CONFIG_XEN_DEBUG_FS */
/*
* Just beyond the highest usermode address. STACK_TOP_MAX has a
@@ -229,25 +285,35 @@ void make_lowmem_page_readwrite(void *vaddr)
}
-static bool page_pinned(void *ptr)
+static bool xen_page_pinned(void *ptr)
{
struct page *page = virt_to_page(ptr);
return PagePinned(page);
}
-static void extend_mmu_update(const struct mmu_update *update)
+static void xen_extend_mmu_update(const struct mmu_update *update)
{
struct multicall_space mcs;
struct mmu_update *u;
mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
- if (mcs.mc != NULL)
+ if (mcs.mc != NULL) {
+ ADD_STATS(mmu_update_extended, 1);
+ ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
+
mcs.mc->args[1]++;
- else {
+
+ if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
+ ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
+ else
+ ADD_STATS(mmu_update_histo[0], 1);
+ } else {
+ ADD_STATS(mmu_update, 1);
mcs = __xen_mc_entry(sizeof(*u));
MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+ ADD_STATS(mmu_update_histo[1], 1);
}
u = mcs.args;
@@ -265,7 +331,9 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
/* ptr may be ioremapped for 64-bit pagetable setup */
u.ptr = arbitrary_virt_to_machine(ptr).maddr;
u.val = pmd_val_ma(val);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
+
+ ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
xen_mc_issue(PARAVIRT_LAZY_MMU);
@@ -274,13 +342,17 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
void xen_set_pmd(pmd_t *ptr, pmd_t val)
{
+ ADD_STATS(pmd_update, 1);
+
/* If page is not pinned, we can just update the entry
directly */
- if (!page_pinned(ptr)) {
+ if (!xen_page_pinned(ptr)) {
*ptr = val;
return;
}
+ ADD_STATS(pmd_update_pinned, 1);
+
xen_set_pmd_hyper(ptr, val);
}
@@ -300,12 +372,18 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
if (mm == &init_mm)
preempt_disable();
+ ADD_STATS(set_pte_at, 1);
+// ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
+ ADD_STATS(set_pte_at_current, mm == current->mm);
+ ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+
if (mm == current->mm || mm == &init_mm) {
if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
struct multicall_space mcs;
mcs = xen_mc_entry(0);
MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+ ADD_STATS(set_pte_at_batched, 1);
xen_mc_issue(PARAVIRT_LAZY_MMU);
goto out;
} else
@@ -334,7 +412,10 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
u.val = pte_val_ma(pte);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
+
+ ADD_STATS(prot_commit, 1);
+ ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
xen_mc_issue(PARAVIRT_LAZY_MMU);
}
@@ -400,7 +481,9 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
/* ptr may be ioremapped for 64-bit pagetable setup */
u.ptr = arbitrary_virt_to_machine(ptr).maddr;
u.val = pud_val_ma(val);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
+
+ ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
xen_mc_issue(PARAVIRT_LAZY_MMU);
@@ -409,18 +492,26 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
void xen_set_pud(pud_t *ptr, pud_t val)
{
+ ADD_STATS(pud_update, 1);
+
/* If page is not pinned, we can just update the entry
directly */
- if (!page_pinned(ptr)) {
+ if (!xen_page_pinned(ptr)) {
*ptr = val;
return;
}
+ ADD_STATS(pud_update_pinned, 1);
+
xen_set_pud_hyper(ptr, val);
}
void xen_set_pte(pte_t *ptep, pte_t pte)
{
+ ADD_STATS(pte_update, 1);
+// ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
+ ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
#ifdef CONFIG_X86_PAE
ptep->pte_high = pte.pte_high;
smp_wmb();
@@ -490,7 +581,7 @@ static void __xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
u.ptr = virt_to_machine(ptr).maddr;
u.val = pgd_val_ma(val);
- extend_mmu_update(&u);
+ xen_extend_mmu_update(&u);
}
/*
@@ -517,17 +608,22 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
{
pgd_t *user_ptr = xen_get_user_pgd(ptr);
+ ADD_STATS(pgd_update, 1);
+
/* If page is not pinned, we can just update the entry
directly */
- if (!page_pinned(ptr)) {
+ if (!xen_page_pinned(ptr)) {
*ptr = val;
if (user_ptr) {
- WARN_ON(page_pinned(user_ptr));
+ WARN_ON(xen_page_pinned(user_ptr));
*user_ptr = val;
}
return;
}
+ ADD_STATS(pgd_update_pinned, 1);
+ ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
/* If it's pinned, then we can at least batch the kernel and
user updates together. */
xen_mc_batch();
@@ -555,9 +651,12 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
* For 64-bit, we must skip the Xen hole in the middle of the address
* space, just after the big x86-64 virtual hole.
*/
-static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
- unsigned long limit)
+static int xen_pgd_walk(struct mm_struct *mm,
+ int (*func)(struct mm_struct *mm, struct page *,
+ enum pt_level),
+ unsigned long limit)
{
+ pgd_t *pgd = mm->pgd;
int flush = 0;
unsigned hole_low, hole_high;
unsigned pgdidx_limit, pudidx_limit, pmdidx_limit;
@@ -590,8 +689,6 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
pmdidx_limit = 0;
#endif
- flush |= (*func)(virt_to_page(pgd), PT_PGD);
-
for (pgdidx = 0; pgdidx <= pgdidx_limit; pgdidx++) {
pud_t *pud;
@@ -604,7 +701,7 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
pud = pud_offset(&pgd[pgdidx], 0);
if (PTRS_PER_PUD > 1) /* not folded */
- flush |= (*func)(virt_to_page(pud), PT_PUD);
+ flush |= (*func)(mm, virt_to_page(pud), PT_PUD);
for (pudidx = 0; pudidx < PTRS_PER_PUD; pudidx++) {
pmd_t *pmd;
@@ -619,7 +716,7 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
pmd = pmd_offset(&pud[pudidx], 0);
if (PTRS_PER_PMD > 1) /* not folded */
- flush |= (*func)(virt_to_page(pmd), PT_PMD);
+ flush |= (*func)(mm, virt_to_page(pmd), PT_PMD);
for (pmdidx = 0; pmdidx < PTRS_PER_PMD; pmdidx++) {
struct page *pte;
@@ -633,28 +730,34 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
continue;
pte = pmd_page(pmd[pmdidx]);
- flush |= (*func)(pte, PT_PTE);
+ flush |= (*func)(mm, pte, PT_PTE);
}
}
}
+
out:
+ /* Do the top level last, so that the callbacks can use it as
+ a cue to do final things like tlb flushes. */
+ flush |= (*func)(mm, virt_to_page(pgd), PT_PGD);
return flush;
}
-static spinlock_t *lock_pte(struct page *page)
+/* If we're using split pte locks, then take the page's lock and
+ return a pointer to it. Otherwise return NULL. */
+static spinlock_t *xen_pte_lock(struct page *page, struct mm_struct *mm)
{
spinlock_t *ptl = NULL;
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
ptl = __pte_lockptr(page);
- spin_lock(ptl);
+ spin_lock_nest_lock(ptl, &mm->page_table_lock);
#endif
return ptl;
}
-static void do_unlock(void *v)
+static void xen_pte_unlock(void *v)
{
spinlock_t *ptl = v;
spin_unlock(ptl);
@@ -672,7 +775,8 @@ static void xen_do_pin(unsigned level, unsigned long pfn)
MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
}
-static int pin_page(struct page *page, enum pt_level level)
+static int xen_pin_page(struct mm_struct *mm, struct page *page,
+ enum pt_level level)
{
unsigned pgfl = TestSetPagePinned(page);
int flush;
@@ -691,21 +795,40 @@ static int pin_page(struct page *page, enum pt_level level)
flush = 0;
+ /*
+ * We need to hold the pagetable lock between the time
+ * we make the pagetable RO and when we actually pin
+ * it. If we don't, then other users may come in and
+ * attempt to update the pagetable by writing it,
+ * which will fail because the memory is RO but not
+ * pinned, so Xen won't do the trap'n'emulate.
+ *
+ * If we're using split pte locks, we can't hold the
+ * entire pagetable's worth of locks during the
+ * traverse, because we may wrap the preempt count (8
+ * bits). The solution is to mark RO and pin each PTE
+ * page while holding the lock. This means the number
+ * of locks we end up holding is never more than a
+ * batch size (~32 entries, at present).
+ *
+ * If we're not using split pte locks, we needn't pin
+ * the PTE pages independently, because we're
+ * protected by the overall pagetable lock.
+ */
ptl = NULL;
if (level == PT_PTE)
- ptl = lock_pte(page);
+ ptl = xen_pte_lock(page, mm);
MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
pfn_pte(pfn, PAGE_KERNEL_RO),
level == PT_PGD ? UVMF_TLB_FLUSH : 0);
- if (level == PT_PTE)
+ if (ptl) {
xen_do_pin(MMUEXT_PIN_L1_TABLE, pfn);
- if (ptl) {
/* Queue a deferred unlock for when this batch
is completed. */
- xen_mc_callback(do_unlock, ptl);
+ xen_mc_callback(xen_pte_unlock, ptl);
}
}
@@ -715,11 +838,11 @@ static int pin_page(struct page *page, enum pt_level level)
/* This is called just after a mm has been created, but it has not
been used yet. We need to make sure that its pagetable is all
read-only, and can be pinned. */
-void xen_pgd_pin(pgd_t *pgd)
+static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
{
xen_mc_batch();
- if (pgd_walk(pgd, pin_page, USER_LIMIT)) {
+ if (xen_pgd_walk(mm, xen_pin_page, USER_LIMIT)) {
/* re-enable interrupts for kmap_flush_unused */
xen_mc_issue(0);
kmap_flush_unused();
@@ -733,25 +856,35 @@ void xen_pgd_pin(pgd_t *pgd)
xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(pgd)));
if (user_pgd) {
- pin_page(virt_to_page(user_pgd), PT_PGD);
+ xen_pin_page(mm, virt_to_page(user_pgd), PT_PGD);
xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd)));
}
}
#else /* CONFIG_X86_32 */
#ifdef CONFIG_X86_PAE
/* Need to make sure unshared kernel PMD is pinnable */
- pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+ xen_pin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+ PT_PMD);
#endif
xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd)));
#endif /* CONFIG_X86_64 */
xen_mc_issue(0);
}
+static void xen_pgd_pin(struct mm_struct *mm)
+{
+ __xen_pgd_pin(mm, mm->pgd);
+}
+
/*
* On save, we need to pin all pagetables to make sure they get their
* mfns turned into pfns. Search the list for any unpinned pgds and pin
* them (unpinned pgds are not currently in use, probably because the
* process is under construction or destruction).
+ *
+ * Expected to be called in stop_machine() ("equivalent to taking
+ * every spinlock in the system"), so the locking doesn't really
+ * matter all that much.
*/
void xen_mm_pin_all(void)
{
@@ -762,7 +895,7 @@ void xen_mm_pin_all(void)
list_for_each_entry(page, &pgd_list, lru) {
if (!PagePinned(page)) {
- xen_pgd_pin((pgd_t *)page_address(page));
+ __xen_pgd_pin(&init_mm, (pgd_t *)page_address(page));
SetPageSavePinned(page);
}
}
@@ -775,7 +908,8 @@ void xen_mm_pin_all(void)
* that's before we have page structures to store the bits. So do all
* the book-keeping now.
*/
-static __init int mark_pinned(struct page *page, enum pt_level level)
+static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
+ enum pt_level level)
{
SetPagePinned(page);
return 0;
@@ -783,10 +917,11 @@ static __init int mark_pinned(struct page *page, enum pt_level level)
void __init xen_mark_init_mm_pinned(void)
{
- pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+ xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
}
-static int unpin_page(struct page *page, enum pt_level level)
+static int xen_unpin_page(struct mm_struct *mm, struct page *page,
+ enum pt_level level)
{
unsigned pgfl = TestClearPagePinned(page);
@@ -796,10 +931,18 @@ static int unpin_page(struct page *page, enum pt_level level)
spinlock_t *ptl = NULL;
struct multicall_space mcs;
+ /*
+ * Do the converse to pin_page. If we're using split
+ * pte locks, we must be holding the lock for while
+ * the pte page is unpinned but still RO to prevent
+ * concurrent updates from seeing it in this
+ * partially-pinned state.
+ */
if (level == PT_PTE) {
- ptl = lock_pte(page);
+ ptl = xen_pte_lock(page, mm);
- xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
+ if (ptl)
+ xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
}
mcs = __xen_mc_entry(0);
@@ -810,7 +953,7 @@ static int unpin_page(struct page *page, enum pt_level level)
if (ptl) {
/* unlock when batch completed */
- xen_mc_callback(do_unlock, ptl);
+ xen_mc_callback(xen_pte_unlock, ptl);
}
}
@@ -818,7 +961,7 @@ static int unpin_page(struct page *page, enum pt_level level)
}
/* Release a pagetables pages back as normal RW */
-static void xen_pgd_unpin(pgd_t *pgd)
+static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd)
{
xen_mc_batch();
@@ -830,21 +973,27 @@ static void xen_pgd_unpin(pgd_t *pgd)
if (user_pgd) {
xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd)));
- unpin_page(virt_to_page(user_pgd), PT_PGD);
+ xen_unpin_page(mm, virt_to_page(user_pgd), PT_PGD);
}
}
#endif
#ifdef CONFIG_X86_PAE
/* Need to make sure unshared kernel PMD is unpinned */
- pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+ xen_unpin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+ PT_PMD);
#endif
- pgd_walk(pgd, unpin_page, USER_LIMIT);
+ xen_pgd_walk(mm, xen_unpin_page, USER_LIMIT);
xen_mc_issue(0);
}
+static void xen_pgd_unpin(struct mm_struct *mm)
+{
+ __xen_pgd_unpin(mm, mm->pgd);
+}
+
/*
* On resume, undo any pinning done at save, so that the rest of the
* kernel doesn't see any unexpected pinned pagetables.
@@ -859,7 +1008,7 @@ void xen_mm_unpin_all(void)
list_for_each_entry(page, &pgd_list, lru) {
if (PageSavePinned(page)) {
BUG_ON(!PagePinned(page));
- xen_pgd_unpin((pgd_t *)page_address(page));
+ __xen_pgd_unpin(&init_mm, (pgd_t *)page_address(page));
ClearPageSavePinned(page);
}
}
@@ -870,14 +1019,14 @@ void xen_mm_unpin_all(void)
void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
spin_lock(&next->page_table_lock);
- xen_pgd_pin(next->pgd);
+ xen_pgd_pin(next);
spin_unlock(&next->page_table_lock);
}
void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
{
spin_lock(&mm->page_table_lock);
- xen_pgd_pin(mm->pgd);
+ xen_pgd_pin(mm);
spin_unlock(&mm->page_table_lock);
}
@@ -907,7 +1056,7 @@ static void drop_other_mm_ref(void *info)
}
}
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
{
cpumask_t mask;
unsigned cpu;
@@ -937,7 +1086,7 @@ static void drop_mm_ref(struct mm_struct *mm)
smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
}
#else
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
{
if (current->active_mm == mm)
load_cr3(swapper_pg_dir);
@@ -961,14 +1110,77 @@ static void drop_mm_ref(struct mm_struct *mm)
void xen_exit_mmap(struct mm_struct *mm)
{
get_cpu(); /* make sure we don't move around */
- drop_mm_ref(mm);
+ xen_drop_mm_ref(mm);
put_cpu();
spin_lock(&mm->page_table_lock);
/* pgd may not be pinned in the error exit path of execve */
- if (page_pinned(mm->pgd))
- xen_pgd_unpin(mm->pgd);
+ if (xen_page_pinned(mm->pgd))
+ xen_pgd_unpin(mm);
spin_unlock(&mm->page_table_lock);
}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mmu_debug;
+
+static int __init xen_mmu_debugfs(void)
+{
+ struct dentry *d_xen = xen_init_debugfs();
+
+ if (d_xen == NULL)
+ return -ENOMEM;
+
+ d_mmu_debug = debugfs_create_dir("mmu", d_xen);
+
+ debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
+
+ debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
+ debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
+ &mmu_stats.pgd_update_pinned);
+ debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pgd_update_pinned);
+
+ debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
+ debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
+ &mmu_stats.pud_update_pinned);
+ debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pud_update_pinned);
+
+ debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
+ debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
+ &mmu_stats.pmd_update_pinned);
+ debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pmd_update_pinned);
+
+ debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
+// debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
+// &mmu_stats.pte_update_pinned);
+ debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
+ &mmu_stats.pte_update_pinned);
+
+ debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
+ debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
+ &mmu_stats.mmu_update_extended);
+ xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
+ mmu_stats.mmu_update_histo, 20);
+
+ debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
+ debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
+ &mmu_stats.set_pte_at_batched);
+ debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
+ &mmu_stats.set_pte_at_current);
+ debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
+ &mmu_stats.set_pte_at_kernel);
+
+ debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
+ debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
+ &mmu_stats.prot_commit_batched);
+
+ return 0;
+}
+fs_initcall(xen_mmu_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index 0f59bd03f9e..98d71659da5 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -18,9 +18,6 @@ void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
void xen_exit_mmap(struct mm_struct *mm);
-void xen_pgd_pin(pgd_t *pgd);
-//void xen_pgd_unpin(pgd_t *pgd);
-
pteval_t xen_pte_val(pte_t);
pmdval_t xen_pmd_val(pmd_t);
pgdval_t xen_pgd_val(pgd_t);
diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c
index 9efd1c6c977..8ea8a0d0b0d 100644
--- a/arch/x86/xen/multicalls.c
+++ b/arch/x86/xen/multicalls.c
@@ -21,16 +21,20 @@
*/
#include <linux/percpu.h>
#include <linux/hardirq.h>
+#include <linux/debugfs.h>
#include <asm/xen/hypercall.h>
#include "multicalls.h"
+#include "debugfs.h"
+
+#define MC_BATCH 32
#define MC_DEBUG 1
-#define MC_BATCH 32
#define MC_ARGS (MC_BATCH * 16)
+
struct mc_buffer {
struct multicall_entry entries[MC_BATCH];
#if MC_DEBUG
@@ -47,6 +51,76 @@ struct mc_buffer {
static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
+/* flush reasons 0- slots, 1- args, 2- callbacks */
+enum flush_reasons
+{
+ FL_SLOTS,
+ FL_ARGS,
+ FL_CALLBACKS,
+
+ FL_N_REASONS
+};
+
+#ifdef CONFIG_XEN_DEBUG_FS
+#define NHYPERCALLS 40 /* not really */
+
+static struct {
+ unsigned histo[MC_BATCH+1];
+
+ unsigned issued;
+ unsigned arg_total;
+ unsigned hypercalls;
+ unsigned histo_hypercalls[NHYPERCALLS];
+
+ unsigned flush[FL_N_REASONS];
+} mc_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+ if (unlikely(zero_stats)) {
+ memset(&mc_stats, 0, sizeof(mc_stats));
+ zero_stats = 0;
+ }
+}
+
+static void mc_add_stats(const struct mc_buffer *mc)
+{
+ int i;
+
+ check_zero();
+
+ mc_stats.issued++;
+ mc_stats.hypercalls += mc->mcidx;
+ mc_stats.arg_total += mc->argidx;
+
+ mc_stats.histo[mc->mcidx]++;
+ for(i = 0; i < mc->mcidx; i++) {
+ unsigned op = mc->entries[i].op;
+ if (op < NHYPERCALLS)
+ mc_stats.histo_hypercalls[op]++;
+ }
+}
+
+static void mc_stats_flush(enum flush_reasons idx)
+{
+ check_zero();
+
+ mc_stats.flush[idx]++;
+}
+
+#else /* !CONFIG_XEN_DEBUG_FS */
+
+static inline void mc_add_stats(const struct mc_buffer *mc)
+{
+}
+
+static inline void mc_stats_flush(enum flush_reasons idx)
+{
+}
+#endif /* CONFIG_XEN_DEBUG_FS */
+
void xen_mc_flush(void)
{
struct mc_buffer *b = &__get_cpu_var(mc_buffer);
@@ -60,6 +134,8 @@ void xen_mc_flush(void)
something in the middle */
local_irq_save(flags);
+ mc_add_stats(b);
+
if (b->mcidx) {
#if MC_DEBUG
memcpy(b->debug, b->entries,
@@ -115,6 +191,7 @@ struct multicall_space __xen_mc_entry(size_t args)
if (b->mcidx == MC_BATCH ||
(argidx + args) > MC_ARGS) {
+ mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS);
xen_mc_flush();
argidx = roundup(b->argidx, sizeof(u64));
}
@@ -158,10 +235,44 @@ void xen_mc_callback(void (*fn)(void *), void *data)
struct mc_buffer *b = &__get_cpu_var(mc_buffer);
struct callback *cb;
- if (b->cbidx == MC_BATCH)
+ if (b->cbidx == MC_BATCH) {
+ mc_stats_flush(FL_CALLBACKS);
xen_mc_flush();
+ }
cb = &b->callbacks[b->cbidx++];
cb->fn = fn;
cb->data = data;
}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mc_debug;
+
+static int __init xen_mc_debugfs(void)
+{
+ struct dentry *d_xen = xen_init_debugfs();
+
+ if (d_xen == NULL)
+ return -ENOMEM;
+
+ d_mc_debug = debugfs_create_dir("multicalls", d_xen);
+
+ debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats);
+
+ debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued);
+ debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls);
+ debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total);
+
+ xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug,
+ mc_stats.histo, MC_BATCH);
+ xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug,
+ mc_stats.histo_hypercalls, NHYPERCALLS);
+ xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug,
+ mc_stats.flush, FL_N_REASONS);
+
+ return 0;
+}
+fs_initcall(xen_mc_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index d8faf79a0a1..d77da613b1d 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -11,11 +11,8 @@
* useful topology information for the kernel to make use of. As a
* result, all CPUs are treated as if they're single-core and
* single-threaded.
- *
- * This does not handle HOTPLUG_CPU yet.
*/
#include <linux/sched.h>
-#include <linux/kernel_stat.h>
#include <linux/err.h>
#include <linux/smp.h>
@@ -36,8 +33,6 @@
#include "xen-ops.h"
#include "mmu.h"
-static void __cpuinit xen_init_lock_cpu(int cpu);
-
cpumask_t xen_cpu_initialized_map;
static DEFINE_PER_CPU(int, resched_irq);
@@ -64,11 +59,12 @@ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static __cpuinit void cpu_bringup_and_idle(void)
+static __cpuinit void cpu_bringup(void)
{
int cpu = smp_processor_id();
cpu_init();
+ touch_softlockup_watchdog();
preempt_disable();
xen_enable_sysenter();
@@ -89,6 +85,11 @@ static __cpuinit void cpu_bringup_and_idle(void)
local_irq_enable();
wmb(); /* make sure everything is out */
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+ cpu_bringup();
cpu_idle();
}
@@ -212,8 +213,6 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
cpu_set(cpu, cpu_present_map);
}
-
- //init_xenbus_allowed_cpumask();
}
static __cpuinit int
@@ -281,12 +280,6 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
struct task_struct *idle = idle_task(cpu);
int rc;
-#if 0
- rc = cpu_up_check(cpu);
- if (rc)
- return rc;
-#endif
-
#ifdef CONFIG_X86_64
/* Allocate node local memory for AP pdas */
WARN_ON(cpu == 0);
@@ -339,6 +332,60 @@ static void xen_smp_cpus_done(unsigned int max_cpus)
{
}
+#ifdef CONFIG_HOTPLUG_CPU
+static int xen_cpu_disable(void)
+{
+ unsigned int cpu = smp_processor_id();
+ if (cpu == 0)
+ return -EBUSY;
+
+ cpu_disable_common();
+
+ load_cr3(swapper_pg_dir);
+ return 0;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+ while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+ }
+ unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+ unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+ unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
+ unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+ xen_uninit_lock_cpu(cpu);
+ xen_teardown_timer(cpu);
+
+ if (num_online_cpus() == 1)
+ alternatives_smp_switch(0);
+}
+
+static void xen_play_dead(void)
+{
+ play_dead_common();
+ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+ cpu_bringup();
+}
+
+#else /* !CONFIG_HOTPLUG_CPU */
+static int xen_cpu_disable(void)
+{
+ return -ENOSYS;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+ BUG();
+}
+
+static void xen_play_dead(void)
+{
+ BUG();
+}
+
+#endif
static void stop_self(void *v)
{
int cpu = smp_processor_id();
@@ -419,176 +466,16 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-struct xen_spinlock {
- unsigned char lock; /* 0 -> free; 1 -> locked */
- unsigned short spinners; /* count of waiting cpus */
-};
-
-static int xen_spin_is_locked(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
- return xl->lock != 0;
-}
-
-static int xen_spin_is_contended(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
- /* Not strictly true; this is only the count of contended
- lock-takers entering the slow path. */
- return xl->spinners != 0;
-}
-
-static int xen_spin_trylock(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
- u8 old = 1;
-
- asm("xchgb %b0,%1"
- : "+q" (old), "+m" (xl->lock) : : "memory");
-
- return old == 0;
-}
-
-static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
-static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
-
-static inline void spinning_lock(struct xen_spinlock *xl)
-{
- __get_cpu_var(lock_spinners) = xl;
- wmb(); /* set lock of interest before count */
- asm(LOCK_PREFIX " incw %0"
- : "+m" (xl->spinners) : : "memory");
-}
-
-static inline void unspinning_lock(struct xen_spinlock *xl)
-{
- asm(LOCK_PREFIX " decw %0"
- : "+m" (xl->spinners) : : "memory");
- wmb(); /* decrement count before clearing lock */
- __get_cpu_var(lock_spinners) = NULL;
-}
-
-static noinline int xen_spin_lock_slow(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
- int irq = __get_cpu_var(lock_kicker_irq);
- int ret;
-
- /* If kicker interrupts not initialized yet, just spin */
- if (irq == -1)
- return 0;
-
- /* announce we're spinning */
- spinning_lock(xl);
-
- /* clear pending */
- xen_clear_irq_pending(irq);
-
- /* check again make sure it didn't become free while
- we weren't looking */
- ret = xen_spin_trylock(lock);
- if (ret)
- goto out;
-
- /* block until irq becomes pending */
- xen_poll_irq(irq);
- kstat_this_cpu.irqs[irq]++;
-
-out:
- unspinning_lock(xl);
- return ret;
-}
-
-static void xen_spin_lock(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
- int timeout;
- u8 oldval;
-
- do {
- timeout = 1 << 10;
-
- asm("1: xchgb %1,%0\n"
- " testb %1,%1\n"
- " jz 3f\n"
- "2: rep;nop\n"
- " cmpb $0,%0\n"
- " je 1b\n"
- " dec %2\n"
- " jnz 2b\n"
- "3:\n"
- : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
- : "1" (1)
- : "memory");
-
- } while (unlikely(oldval != 0 && !xen_spin_lock_slow(lock)));
-}
-
-static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
-{
- int cpu;
-
- for_each_online_cpu(cpu) {
- /* XXX should mix up next cpu selection */
- if (per_cpu(lock_spinners, cpu) == xl) {
- xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
- break;
- }
- }
-}
-
-static void xen_spin_unlock(struct raw_spinlock *lock)
-{
- struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
- smp_wmb(); /* make sure no writes get moved after unlock */
- xl->lock = 0; /* release lock */
-
- /* make sure unlock happens before kick */
- barrier();
-
- if (unlikely(xl->spinners))
- xen_spin_unlock_slow(xl);
-}
-
-static __cpuinit void xen_init_lock_cpu(int cpu)
-{
- int irq;
- const char *name;
-
- name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
- irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
- cpu,
- xen_reschedule_interrupt,
- IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
- name,
- NULL);
-
- if (irq >= 0) {
- disable_irq(irq); /* make sure it's never delivered */
- per_cpu(lock_kicker_irq, cpu) = irq;
- }
-
- printk("cpu %d spinlock event irq %d\n", cpu, irq);
-}
-
-static void __init xen_init_spinlocks(void)
-{
- pv_lock_ops.spin_is_locked = xen_spin_is_locked;
- pv_lock_ops.spin_is_contended = xen_spin_is_contended;
- pv_lock_ops.spin_lock = xen_spin_lock;
- pv_lock_ops.spin_trylock = xen_spin_trylock;
- pv_lock_ops.spin_unlock = xen_spin_unlock;
-}
-
static const struct smp_ops xen_smp_ops __initdata = {
.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
.smp_prepare_cpus = xen_smp_prepare_cpus,
- .cpu_up = xen_cpu_up,
.smp_cpus_done = xen_smp_cpus_done,
+ .cpu_up = xen_cpu_up,
+ .cpu_die = xen_cpu_die,
+ .cpu_disable = xen_cpu_disable,
+ .play_dead = xen_play_dead,
+
.smp_send_stop = xen_smp_send_stop,
.smp_send_reschedule = xen_smp_send_reschedule,
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
new file mode 100644
index 00000000000..dd71e3a021c
--- /dev/null
+++ b/arch/x86/xen/spinlock.c
@@ -0,0 +1,428 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/log2.h>
+
+#include <asm/paravirt.h>
+
+#include <xen/interface/xen.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "debugfs.h"
+
+#ifdef CONFIG_XEN_DEBUG_FS
+static struct xen_spinlock_stats
+{
+ u64 taken;
+ u32 taken_slow;
+ u32 taken_slow_nested;
+ u32 taken_slow_pickup;
+ u32 taken_slow_spurious;
+ u32 taken_slow_irqenable;
+
+ u64 released;
+ u32 released_slow;
+ u32 released_slow_kicked;
+
+#define HISTO_BUCKETS 30
+ u32 histo_spin_total[HISTO_BUCKETS+1];
+ u32 histo_spin_spinning[HISTO_BUCKETS+1];
+ u32 histo_spin_blocked[HISTO_BUCKETS+1];
+
+ u64 time_total;
+ u64 time_spinning;
+ u64 time_blocked;
+} spinlock_stats;
+
+static u8 zero_stats;
+
+static unsigned lock_timeout = 1 << 10;
+#define TIMEOUT lock_timeout
+
+static inline void check_zero(void)
+{
+ if (unlikely(zero_stats)) {
+ memset(&spinlock_stats, 0, sizeof(spinlock_stats));
+ zero_stats = 0;
+ }
+}
+
+#define ADD_STATS(elem, val) \
+ do { check_zero(); spinlock_stats.elem += (val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+ return xen_clocksource_read();
+}
+
+static void __spin_time_accum(u64 delta, u32 *array)
+{
+ unsigned index = ilog2(delta);
+
+ check_zero();
+
+ if (index < HISTO_BUCKETS)
+ array[index]++;
+ else
+ array[HISTO_BUCKETS]++;
+}
+
+static inline void spin_time_accum_spinning(u64 start)
+{
+ u32 delta = xen_clocksource_read() - start;
+
+ __spin_time_accum(delta, spinlock_stats.histo_spin_spinning);
+ spinlock_stats.time_spinning += delta;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+ u32 delta = xen_clocksource_read() - start;
+
+ __spin_time_accum(delta, spinlock_stats.histo_spin_total);
+ spinlock_stats.time_total += delta;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+ u32 delta = xen_clocksource_read() - start;
+
+ __spin_time_accum(delta, spinlock_stats.histo_spin_blocked);
+ spinlock_stats.time_blocked += delta;
+}
+#else /* !CONFIG_XEN_DEBUG_FS */
+#define TIMEOUT (1 << 10)
+#define ADD_STATS(elem, val) do { (void)(val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+ return 0;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+}
+static inline void spin_time_accum_spinning(u64 start)
+{
+}
+static inline void spin_time_accum_blocked(u64 start)
+{
+}
+#endif /* CONFIG_XEN_DEBUG_FS */
+
+struct xen_spinlock {
+ unsigned char lock; /* 0 -> free; 1 -> locked */
+ unsigned short spinners; /* count of waiting cpus */
+};
+
+static int xen_spin_is_locked(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+ return xl->lock != 0;
+}
+
+static int xen_spin_is_contended(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+ /* Not strictly true; this is only the count of contended
+ lock-takers entering the slow path. */
+ return xl->spinners != 0;
+}
+
+static int xen_spin_trylock(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+ u8 old = 1;
+
+ asm("xchgb %b0,%1"
+ : "+q" (old), "+m" (xl->lock) : : "memory");
+
+ return old == 0;
+}
+
+static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
+static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
+
+/*
+ * Mark a cpu as interested in a lock. Returns the CPU's previous
+ * lock of interest, in case we got preempted by an interrupt.
+ */
+static inline struct xen_spinlock *spinning_lock(struct xen_spinlock *xl)
+{
+ struct xen_spinlock *prev;
+
+ prev = __get_cpu_var(lock_spinners);
+ __get_cpu_var(lock_spinners) = xl;
+
+ wmb(); /* set lock of interest before count */
+
+ asm(LOCK_PREFIX " incw %0"
+ : "+m" (xl->spinners) : : "memory");
+
+ return prev;
+}
+
+/*
+ * Mark a cpu as no longer interested in a lock. Restores previous
+ * lock of interest (NULL for none).
+ */
+static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock *prev)
+{
+ asm(LOCK_PREFIX " decw %0"
+ : "+m" (xl->spinners) : : "memory");
+ wmb(); /* decrement count before restoring lock */
+ __get_cpu_var(lock_spinners) = prev;
+}
+
+static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enable)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+ struct xen_spinlock *prev;
+ int irq = __get_cpu_var(lock_kicker_irq);
+ int ret;
+ unsigned long flags;
+ u64 start;
+
+ /* If kicker interrupts not initialized yet, just spin */
+ if (irq == -1)
+ return 0;
+
+ start = spin_time_start();
+
+ /* announce we're spinning */
+ prev = spinning_lock(xl);
+
+ flags = __raw_local_save_flags();
+ if (irq_enable) {
+ ADD_STATS(taken_slow_irqenable, 1);
+ raw_local_irq_enable();
+ }
+
+ ADD_STATS(taken_slow, 1);
+ ADD_STATS(taken_slow_nested, prev != NULL);
+
+ do {
+ /* clear pending */
+ xen_clear_irq_pending(irq);
+
+ /* check again make sure it didn't become free while
+ we weren't looking */
+ ret = xen_spin_trylock(lock);
+ if (ret) {
+ ADD_STATS(taken_slow_pickup, 1);
+
+ /*
+ * If we interrupted another spinlock while it
+ * was blocking, make sure it doesn't block
+ * without rechecking the lock.
+ */
+ if (prev != NULL)
+ xen_set_irq_pending(irq);
+ goto out;
+ }
+
+ /*
+ * Block until irq becomes pending. If we're
+ * interrupted at this point (after the trylock but
+ * before entering the block), then the nested lock
+ * handler guarantees that the irq will be left
+ * pending if there's any chance the lock became free;
+ * xen_poll_irq() returns immediately if the irq is
+ * pending.
+ */
+ xen_poll_irq(irq);
+ ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq));
+ } while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */
+
+ kstat_this_cpu.irqs[irq]++;
+
+out:
+ raw_local_irq_restore(flags);
+ unspinning_lock(xl, prev);
+ spin_time_accum_blocked(start);
+
+ return ret;
+}
+
+static inline void __xen_spin_lock(struct raw_spinlock *lock, bool irq_enable)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+ unsigned timeout;
+ u8 oldval;
+ u64 start_spin;
+
+ ADD_STATS(taken, 1);
+
+ start_spin = spin_time_start();
+
+ do {
+ u64 start_spin_fast = spin_time_start();
+
+ timeout = TIMEOUT;
+
+ asm("1: xchgb %1,%0\n"
+ " testb %1,%1\n"
+ " jz 3f\n"
+ "2: rep;nop\n"
+ " cmpb $0,%0\n"
+ " je 1b\n"
+ " dec %2\n"
+ " jnz 2b\n"
+ "3:\n"
+ : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
+ : "1" (1)
+ : "memory");
+
+ spin_time_accum_spinning(start_spin_fast);
+
+ } while (unlikely(oldval != 0 &&
+ (TIMEOUT == ~0 || !xen_spin_lock_slow(lock, irq_enable))));
+
+ spin_time_accum_total(start_spin);
+}
+
+static void xen_spin_lock(struct raw_spinlock *lock)
+{
+ __xen_spin_lock(lock, false);
+}
+
+static void xen_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+ __xen_spin_lock(lock, !raw_irqs_disabled_flags(flags));
+}
+
+static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
+{
+ int cpu;
+
+ ADD_STATS(released_slow, 1);
+
+ for_each_online_cpu(cpu) {
+ /* XXX should mix up next cpu selection */
+ if (per_cpu(lock_spinners, cpu) == xl) {
+ ADD_STATS(released_slow_kicked, 1);
+ xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
+ break;
+ }
+ }
+}
+
+static void xen_spin_unlock(struct raw_spinlock *lock)
+{
+ struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+ ADD_STATS(released, 1);
+
+ smp_wmb(); /* make sure no writes get moved after unlock */
+ xl->lock = 0; /* release lock */
+
+ /* make sure unlock happens before kick */
+ barrier();
+
+ if (unlikely(xl->spinners))
+ xen_spin_unlock_slow(xl);
+}
+
+static irqreturn_t dummy_handler(int irq, void *dev_id)
+{
+ BUG();
+ return IRQ_HANDLED;
+}
+
+void __cpuinit xen_init_lock_cpu(int cpu)
+{
+ int irq;
+ const char *name;
+
+ name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
+ irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
+ cpu,
+ dummy_handler,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ name,
+ NULL);
+
+ if (irq >= 0) {
+ disable_irq(irq); /* make sure it's never delivered */
+ per_cpu(lock_kicker_irq, cpu) = irq;
+ }
+
+ printk("cpu %d spinlock event irq %d\n", cpu, irq);
+}
+
+void xen_uninit_lock_cpu(int cpu)
+{
+ unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+}
+
+void __init xen_init_spinlocks(void)
+{
+ pv_lock_ops.spin_is_locked = xen_spin_is_locked;
+ pv_lock_ops.spin_is_contended = xen_spin_is_contended;
+ pv_lock_ops.spin_lock = xen_spin_lock;
+ pv_lock_ops.spin_lock_flags = xen_spin_lock_flags;
+ pv_lock_ops.spin_trylock = xen_spin_trylock;
+ pv_lock_ops.spin_unlock = xen_spin_unlock;
+}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_spin_debug;
+
+static int __init xen_spinlock_debugfs(void)
+{
+ struct dentry *d_xen = xen_init_debugfs();
+
+ if (d_xen == NULL)
+ return -ENOMEM;
+
+ d_spin_debug = debugfs_create_dir("spinlocks", d_xen);
+
+ debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
+
+ debugfs_create_u32("timeout", 0644, d_spin_debug, &lock_timeout);
+
+ debugfs_create_u64("taken", 0444, d_spin_debug, &spinlock_stats.taken);
+ debugfs_create_u32("taken_slow", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow);
+ debugfs_create_u32("taken_slow_nested", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_nested);
+ debugfs_create_u32("taken_slow_pickup", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_pickup);
+ debugfs_create_u32("taken_slow_spurious", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_spurious);
+ debugfs_create_u32("taken_slow_irqenable", 0444, d_spin_debug,
+ &spinlock_stats.taken_slow_irqenable);
+
+ debugfs_create_u64("released", 0444, d_spin_debug, &spinlock_stats.released);
+ debugfs_create_u32("released_slow", 0444, d_spin_debug,
+ &spinlock_stats.released_slow);
+ debugfs_create_u32("released_slow_kicked", 0444, d_spin_debug,
+ &spinlock_stats.released_slow_kicked);
+
+ debugfs_create_u64("time_spinning", 0444, d_spin_debug,
+ &spinlock_stats.time_spinning);
+ debugfs_create_u64("time_blocked", 0444, d_spin_debug,
+ &spinlock_stats.time_blocked);
+ debugfs_create_u64("time_total", 0444, d_spin_debug,
+ &spinlock_stats.time_total);
+
+ xen_debugfs_create_u32_array("histo_total", 0444, d_spin_debug,
+ spinlock_stats.histo_spin_total, HISTO_BUCKETS + 1);
+ xen_debugfs_create_u32_array("histo_spinning", 0444, d_spin_debug,
+ spinlock_stats.histo_spin_spinning, HISTO_BUCKETS + 1);
+ xen_debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
+ spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
+
+ return 0;
+}
+fs_initcall(xen_spinlock_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 685b77470fc..004ba86326a 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -30,8 +30,6 @@
#define TIMER_SLOP 100000
#define NS_PER_TICK (1000000000LL / HZ)
-static cycle_t xen_clocksource_read(void);
-
/* runstate info updated by Xen */
static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
@@ -213,7 +211,7 @@ unsigned long xen_tsc_khz(void)
return xen_khz;
}
-static cycle_t xen_clocksource_read(void)
+cycle_t xen_clocksource_read(void)
{
struct pvclock_vcpu_time_info *src;
cycle_t ret;
@@ -452,6 +450,14 @@ void xen_setup_timer(int cpu)
setup_runstate_info(cpu);
}
+void xen_teardown_timer(int cpu)
+{
+ struct clock_event_device *evt;
+ BUG_ON(cpu == 0);
+ evt = &per_cpu(xen_clock_events, cpu);
+ unbind_from_irqhandler(evt->irq, NULL);
+}
+
void xen_setup_cpu_clockevents(void)
{
BUG_ON(preemptible());
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index 2497a30f41d..42786f59d9c 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -298,7 +298,7 @@ check_events:
push %eax
push %ecx
push %edx
- call force_evtchn_callback
+ call xen_force_evtchn_callback
pop %edx
pop %ecx
pop %eax
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S
index 7f58304fafb..05794c566e8 100644
--- a/arch/x86/xen/xen-asm_64.S
+++ b/arch/x86/xen/xen-asm_64.S
@@ -26,8 +26,15 @@
/* Pseudo-flag used for virtual NMI, which we don't implement yet */
#define XEN_EFLAGS_NMI 0x80000000
-#if 0
-#include <asm/percpu.h>
+#if 1
+/*
+ x86-64 does not yet support direct access to percpu variables
+ via a segment override, so we just need to make sure this code
+ never gets used
+ */
+#define BUG ud2a
+#define PER_CPU_VAR(var, off) 0xdeadbeef
+#endif
/*
Enable events. This clears the event mask and tests the pending
@@ -35,6 +42,8 @@
events, then enter the hypervisor to get them handled.
*/
ENTRY(xen_irq_enable_direct)
+ BUG
+
/* Unmask events */
movb $0, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
@@ -58,6 +67,8 @@ ENDPATCH(xen_irq_enable_direct)
non-zero.
*/
ENTRY(xen_irq_disable_direct)
+ BUG
+
movb $1, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
ENDPATCH(xen_irq_disable_direct)
ret
@@ -74,6 +85,8 @@ ENDPATCH(xen_irq_disable_direct)
Xen and x86 use opposite senses (mask vs enable).
*/
ENTRY(xen_save_fl_direct)
+ BUG
+
testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
setz %ah
addb %ah,%ah
@@ -91,6 +104,8 @@ ENDPATCH(xen_save_fl_direct)
if so.
*/
ENTRY(xen_restore_fl_direct)
+ BUG
+
testb $X86_EFLAGS_IF>>8, %ah
setz PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
/* Preempt here doesn't matter because that will deal with
@@ -122,7 +137,7 @@ check_events:
push %r9
push %r10
push %r11
- call force_evtchn_callback
+ call xen_force_evtchn_callback
pop %r11
pop %r10
pop %r9
@@ -133,7 +148,6 @@ check_events:
pop %rcx
pop %rax
ret
-#endif
ENTRY(xen_adjust_exception_frame)
mov 8+0(%rsp),%rcx
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index dd3c23152a2..d7422dc2a55 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -2,6 +2,7 @@
#define XEN_OPS_H
#include <linux/init.h>
+#include <linux/clocksource.h>
#include <linux/irqreturn.h>
#include <xen/xen-ops.h>
@@ -31,7 +32,10 @@ void xen_vcpu_restore(void);
void __init xen_build_dynamic_phys_to_machine(void);
+void xen_init_irq_ops(void);
void xen_setup_timer(int cpu);
+void xen_teardown_timer(int cpu);
+cycle_t xen_clocksource_read(void);
void xen_setup_cpu_clockevents(void);
unsigned long xen_tsc_khz(void);
void __init xen_time_init(void);
@@ -50,6 +54,10 @@ void __init xen_setup_vcpu_info_placement(void);
#ifdef CONFIG_SMP
void xen_smp_init(void);
+void __init xen_init_spinlocks(void);
+__cpuinit void xen_init_lock_cpu(int cpu);
+void xen_uninit_lock_cpu(int cpu);
+
extern cpumask_t xen_cpu_initialized_map;
#else
static inline void xen_smp_init(void) {}
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 12cf5d491f0..da49b006bcc 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -259,7 +259,7 @@ config ACPI_ASUS
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
- depends on X86
+ depends on X86 && INPUT
select INPUT_POLLDEV
select NET
select RFKILL
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 8dd3336efd7..3c578ef78c4 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -369,7 +369,6 @@ static int __init acpi_rtc_init(void)
DBG("RTC unavailable?\n");
return 0;
}
-/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
-fs_initcall(acpi_rtc_init);
+module_init(acpi_rtc_init);
#endif
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index f17cd4b572f..78fbec8ceda 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -7,7 +7,6 @@ menuconfig ATA
depends on HAS_IOMEM
depends on BLOCK
depends on !(M32R || M68K) || BROKEN
- depends on !SUN4 || BROKEN
select SCSI
---help---
If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 73338d231db..937c9c0ef4c 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -47,8 +47,9 @@
#include <asm/atomic.h>
#ifdef CONFIG_SBUS
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/pgtable.h>
@@ -661,249 +662,189 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
#ifdef CONFIG_SBUS
-static u32
-fore200e_sba_read(volatile u32 __iomem *addr)
+static u32 fore200e_sba_read(volatile u32 __iomem *addr)
{
return sbus_readl(addr);
}
-
-static void
-fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
+static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
{
sbus_writel(val, addr);
}
-
-static u32
-fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
+static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction);
+ struct of_device *op = fore200e->bus_dev;
+ u32 dma_addr;
- DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
- virt_addr, size, direction, dma_addr);
+ dma_addr = dma_map_single(&op->dev, virt_addr, size, direction);
+
+ DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
+ virt_addr, size, direction, dma_addr);
- return dma_addr;
+ return dma_addr;
}
-
-static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
- dma_addr, size, direction);
+ struct of_device *op = fore200e->bus_dev;
- sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
-}
+ DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
+ dma_addr, size, direction);
+ dma_unmap_single(&op->dev, dma_addr, size, direction);
+}
-static void
-fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+ struct of_device *op = fore200e->bus_dev;
+
+ DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+ dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction);
}
-static void
-fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-
- sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
-}
+ struct of_device *op = fore200e->bus_dev;
+ DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
- (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
+ dma_sync_single_for_device(&op->dev, dma_addr, size, direction);
+}
-static int
-fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
- int size, int nbr, int alignment)
+/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
+ * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter.
+ */
+static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
+ int size, int nbr, int alignment)
{
- chunk->alloc_size = chunk->align_size = size * nbr;
+ struct of_device *op = fore200e->bus_dev;
- /* returned chunks are page-aligned */
- chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev,
- chunk->alloc_size,
- &chunk->dma_addr);
+ chunk->alloc_size = chunk->align_size = size * nbr;
- if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
- return -ENOMEM;
+ /* returned chunks are page-aligned */
+ chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size,
+ &chunk->dma_addr, GFP_ATOMIC);
- chunk->align_addr = chunk->alloc_addr;
+ if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
+ return -ENOMEM;
+
+ chunk->align_addr = chunk->alloc_addr;
- return 0;
+ return 0;
}
-
/* free a DVMA consistent chunk of memory */
-
-static void
-fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk)
{
- sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev,
- chunk->alloc_size,
- chunk->alloc_addr,
- chunk->dma_addr);
-}
+ struct of_device *op = fore200e->bus_dev;
+ dma_free_coherent(&op->dev, chunk->alloc_size,
+ chunk->alloc_addr, chunk->dma_addr);
+}
-static void
-fore200e_sba_irq_enable(struct fore200e* fore200e)
+static void fore200e_sba_irq_enable(struct fore200e *fore200e)
{
- u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
- fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
+ u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+ fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
}
-
-static int
-fore200e_sba_irq_check(struct fore200e* fore200e)
+static int fore200e_sba_irq_check(struct fore200e *fore200e)
{
- return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
+ return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
}
-
-static void
-fore200e_sba_irq_ack(struct fore200e* fore200e)
+static void fore200e_sba_irq_ack(struct fore200e *fore200e)
{
- u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
- fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
+ u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+ fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
}
-
-static void
-fore200e_sba_reset(struct fore200e* fore200e)
+static void fore200e_sba_reset(struct fore200e *fore200e)
{
- fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
- fore200e_spin(10);
- fore200e->bus->write(0, fore200e->regs.sba.hcr);
+ fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
+ fore200e_spin(10);
+ fore200e->bus->write(0, fore200e->regs.sba.hcr);
}
-
-static int __init
-fore200e_sba_map(struct fore200e* fore200e)
+static int __init fore200e_sba_map(struct fore200e *fore200e)
{
- struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
- unsigned int bursts;
+ struct of_device *op = fore200e->bus_dev;
+ unsigned int bursts;
- /* gain access to the SBA specific registers */
- fore200e->regs.sba.hcr = sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
- fore200e->regs.sba.bsr = sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
- fore200e->regs.sba.isr = sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
- fore200e->virt_base = sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
+ /* gain access to the SBA specific registers */
+ fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
+ fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
+ fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
+ fore200e->virt_base = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
- if (fore200e->virt_base == NULL) {
- printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
- return -EFAULT;
- }
+ if (!fore200e->virt_base) {
+ printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
+ return -EFAULT;
+ }
- DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
+ DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
- fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
+ fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
- /* get the supported DVMA burst sizes */
- bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00);
+ /* get the supported DVMA burst sizes */
+ bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00);
- if (sbus_can_dma_64bit(sbus_dev))
- sbus_set_sbus64(sbus_dev, bursts);
+ if (sbus_can_dma_64bit())
+ sbus_set_sbus64(&op->dev, bursts);
- fore200e->state = FORE200E_STATE_MAP;
- return 0;
+ fore200e->state = FORE200E_STATE_MAP;
+ return 0;
}
-
-static void
-fore200e_sba_unmap(struct fore200e* fore200e)
+static void fore200e_sba_unmap(struct fore200e *fore200e)
{
- sbus_iounmap(fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
- sbus_iounmap(fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
- sbus_iounmap(fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
- sbus_iounmap(fore200e->virt_base, SBA200E_RAM_LENGTH);
-}
+ struct of_device *op = fore200e->bus_dev;
+ of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
+ of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
+ of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
+ of_iounmap(&op->resource[3], fore200e->virt_base, SBA200E_RAM_LENGTH);
+}
-static int __init
-fore200e_sba_configure(struct fore200e* fore200e)
+static int __init fore200e_sba_configure(struct fore200e *fore200e)
{
- fore200e->state = FORE200E_STATE_CONFIGURE;
- return 0;
+ fore200e->state = FORE200E_STATE_CONFIGURE;
+ return 0;
}
-
-static struct fore200e* __init
-fore200e_sba_detect(const struct fore200e_bus* bus, int index)
+static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
{
- struct fore200e* fore200e;
- struct sbus_bus* sbus_bus;
- struct sbus_dev* sbus_dev = NULL;
-
- unsigned int count = 0;
-
- for_each_sbus (sbus_bus) {
- for_each_sbusdev (sbus_dev, sbus_bus) {
- if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) {
- if (count >= index)
- goto found;
- count++;
- }
- }
- }
- return NULL;
-
- found:
- if (sbus_dev->num_registers != 4) {
- printk(FORE200E "this %s device has %d instead of 4 registers\n",
- bus->model_name, sbus_dev->num_registers);
- return NULL;
- }
-
- fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
- if (fore200e == NULL)
- return NULL;
+ struct of_device *op = fore200e->bus_dev;
+ const u8 *prop;
+ int len;
- fore200e->bus = bus;
- fore200e->bus_dev = sbus_dev;
- fore200e->irq = sbus_dev->irqs[ 0 ];
+ prop = of_get_property(op->node, "madaddrlo2", &len);
+ if (!prop)
+ return -ENODEV;
+ memcpy(&prom->mac_addr[4], prop, 4);
- fore200e->phys_base = (unsigned long)sbus_dev;
+ prop = of_get_property(op->node, "madaddrhi4", &len);
+ if (!prop)
+ return -ENODEV;
+ memcpy(&prom->mac_addr[2], prop, 4);
- sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+ prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0);
+ prom->hw_revision = of_getintprop_default(op->node, "promversion", 0);
- return fore200e;
+ return 0;
}
-
-static int __init
-fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom)
+static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
{
- struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev;
- int len;
-
- len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4);
- if (len < 0)
- return -EBUSY;
-
- len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4);
- if (len < 0)
- return -EBUSY;
-
- prom_getproperty(sbus_dev->prom_node, "serialnumber",
- (char*)&prom->serial_number, sizeof(prom->serial_number));
-
- prom_getproperty(sbus_dev->prom_node, "promversion",
- (char*)&prom->hw_revision, sizeof(prom->hw_revision));
-
- return 0;
-}
+ struct of_device *op = fore200e->bus_dev;
+ const struct linux_prom_registers *regs;
+ regs = of_get_property(op->node, "reg", NULL);
-static int
-fore200e_sba_proc_read(struct fore200e* fore200e, char *page)
-{
- struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
-
- return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name);
+ return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n",
+ (regs ? regs->which_io : 0), op->node->name);
}
#endif /* CONFIG_SBUS */
@@ -2572,7 +2513,7 @@ fore200e_load_and_start_fw(struct fore200e* fore200e)
device = &((struct pci_dev *) fore200e->bus_dev)->dev;
#ifdef CONFIG_SBUS
else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0)
- device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev;
+ device = &((struct of_device *) fore200e->bus_dev)->dev;
#endif
else
return err;
@@ -2701,6 +2642,66 @@ fore200e_init(struct fore200e* fore200e)
return 0;
}
+#ifdef CONFIG_SBUS
+static int __devinit fore200e_sba_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ const struct fore200e_bus *bus = match->data;
+ struct fore200e *fore200e;
+ static int index = 0;
+ int err;
+
+ fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
+ if (!fore200e)
+ return -ENOMEM;
+
+ fore200e->bus = bus;
+ fore200e->bus_dev = op;
+ fore200e->irq = op->irqs[0];
+ fore200e->phys_base = op->resource[0].start;
+
+ sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+
+ err = fore200e_init(fore200e);
+ if (err < 0) {
+ fore200e_shutdown(fore200e);
+ kfree(fore200e);
+ return err;
+ }
+
+ index++;
+ dev_set_drvdata(&op->dev, fore200e);
+
+ return 0;
+}
+
+static int __devexit fore200e_sba_remove(struct of_device *op)
+{
+ struct fore200e *fore200e = dev_get_drvdata(&op->dev);
+
+ fore200e_shutdown(fore200e);
+ kfree(fore200e);
+
+ return 0;
+}
+
+static const struct of_device_id fore200e_sba_match[] = {
+ {
+ .name = SBA200E_PROM_NAME,
+ .data = (void *) &fore200e_bus[1],
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fore200e_sba_match);
+
+static struct of_platform_driver fore200e_sba_driver = {
+ .name = "fore_200e",
+ .match_table = fore200e_sba_match,
+ .probe = fore200e_sba_probe,
+ .remove = __devexit_p(fore200e_sba_remove),
+};
+#endif
+
#ifdef CONFIG_PCI
static int __devinit
fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
@@ -2784,67 +2785,40 @@ static struct pci_driver fore200e_pca_driver = {
};
#endif
-
-static int __init
-fore200e_module_init(void)
+static int __init fore200e_module_init(void)
{
- const struct fore200e_bus* bus;
- struct fore200e* fore200e;
- int index;
-
- printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
+ int err;
- /* for each configured bus interface */
- for (bus = fore200e_bus; bus->model_name; bus++) {
+ printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
- /* detect all boards present on that bus */
- for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) {
-
- printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
- fore200e->bus->model_name,
- fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
-
- sprintf(fore200e->name, "%s-%d", bus->model_name, index);
-
- if (fore200e_init(fore200e) < 0) {
-
- fore200e_shutdown(fore200e);
- break;
- }
-
- list_add(&fore200e->entry, &fore200e_boards);
- }
- }
+#ifdef CONFIG_SBUS
+ err = of_register_driver(&fore200e_sba_driver, &of_bus_type);
+ if (err)
+ return err;
+#endif
#ifdef CONFIG_PCI
- if (!pci_register_driver(&fore200e_pca_driver))
- return 0;
+ err = pci_register_driver(&fore200e_pca_driver);
#endif
- if (!list_empty(&fore200e_boards))
- return 0;
+#ifdef CONFIG_SBUS
+ if (err)
+ of_unregister_driver(&fore200e_sba_driver);
+#endif
- return -ENODEV;
+ return err;
}
-
-static void __exit
-fore200e_module_cleanup(void)
+static void __exit fore200e_module_cleanup(void)
{
- struct fore200e *fore200e, *next;
-
#ifdef CONFIG_PCI
- pci_unregister_driver(&fore200e_pca_driver);
+ pci_unregister_driver(&fore200e_pca_driver);
+#endif
+#ifdef CONFIG_SBUS
+ of_unregister_driver(&fore200e_sba_driver);
#endif
-
- list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) {
- fore200e_shutdown(fore200e);
- kfree(fore200e);
- }
- DPRINTK(1, "module being removed\n");
}
-
static int
fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
{
@@ -3163,7 +3137,6 @@ static const struct fore200e_bus fore200e_bus[] = {
fore200e_pca_dma_sync_for_device,
fore200e_pca_dma_chunk_alloc,
fore200e_pca_dma_chunk_free,
- NULL,
fore200e_pca_configure,
fore200e_pca_map,
fore200e_pca_reset,
@@ -3185,7 +3158,6 @@ static const struct fore200e_bus fore200e_bus[] = {
fore200e_sba_dma_sync_for_device,
fore200e_sba_dma_chunk_alloc,
fore200e_sba_dma_chunk_free,
- fore200e_sba_detect,
fore200e_sba_configure,
fore200e_sba_map,
fore200e_sba_reset,
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index 5c6e7adcb19..7f97c09aaea 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -778,9 +778,9 @@ typedef struct fore200e_pca_regs {
/* SBA-200E registers */
typedef struct fore200e_sba_regs {
- volatile u32 __iomem *hcr; /* address of host control register */
- volatile u32 __iomem *bsr; /* address of burst transfer size register */
- volatile u32 __iomem *isr; /* address of interrupt level selection register */
+ u32 __iomem *hcr; /* address of host control register */
+ u32 __iomem *bsr; /* address of burst transfer size register */
+ u32 __iomem *isr; /* address of interrupt level selection register */
} fore200e_sba_regs_t;
@@ -810,7 +810,6 @@ typedef struct fore200e_bus {
void (*dma_sync_for_device)(struct fore200e*, u32, int, int);
int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
void (*dma_chunk_free)(struct fore200e*, struct chunk*);
- struct fore200e* (*detect)(const struct fore200e_bus*, int);
int (*configure)(struct fore200e*);
int (*map)(struct fore200e*);
void (*reset)(struct fore200e*);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index a8de037ecd4..953c0b83d75 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -1,6 +1,6 @@
/* sunvdc.c: Sun LDOM Virtual Disk Client.
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/module.h>
@@ -834,7 +834,7 @@ static int vdc_port_remove(struct vio_dev *vdev)
return 0;
}
-static struct vio_device_id vdc_port_match[] = {
+static const struct vio_device_id vdc_port_match[] = {
{
.type = "vdc-port",
},
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index bff602ccccf..1a50ae70f71 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1066,7 +1066,7 @@ static struct xenbus_driver blkfront = {
static int __init xlblk_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 8dfcf77cb71..4426bb552bd 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
return -EUNATCH;
default:
- err = n_tty_ioctl(tty, file, cmd, arg);
+ err = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
};
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index caff85149b9..700ff967945 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -350,7 +350,7 @@ config STALDRV
config STALLION
tristate "Stallion EasyIO or EC8/32 support"
- depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+ depends on STALDRV && (ISA || EISA || PCI)
help
If you have an EasyIO or EasyConnection 8/32 multiport Stallion
card, then this is for you; say Y. Make sure to read
@@ -361,7 +361,7 @@ config STALLION
config ISTALLION
tristate "Stallion EC8/64, ONboard, Brumby support"
- depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+ depends on STALDRV && (ISA || EISA || PCI)
help
If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
serial multiport card, say Y here. Make sure to read
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 6850f6da757..1a4247dccac 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -7,7 +7,7 @@
#
FONTMAPFILE = cp437.uni
-obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o
+obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 6e763e3f5a8..98821f97583 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -837,9 +837,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
struct async_struct *info;
unsigned long flags;
- if (!tty)
- return 0;
-
info = tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
@@ -892,9 +889,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
struct async_struct *info;
unsigned long flags;
- if (!tty)
- return 0;
-
info = tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_write"))
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 31d08b641f5..b899d9182c7 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -712,8 +712,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
IndexCard = adgl->num_card-1;
- if(cmd != 0 && cmd != 6 &&
- ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+ if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
static int warncount = 10;
if (warncount) {
printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
@@ -832,8 +831,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
break;
default:
- printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
- ret = -EINVAL;
+ ret = -ENOTTY;
break;
}
Dummy = readb(apbs[IndexCard].RamIO + VERS);
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index fe6d774fe2e..5e5b1dc1a0a 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -4993,12 +4993,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
card_name = "Cyclom-Y";
- addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+ addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+ CyPCI_Yctl);
if (addr0 == NULL) {
dev_err(&pdev->dev, "can't remap ctl region\n");
goto err_reg;
}
- addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+ addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+ CyPCI_Ywin);
if (addr2 == NULL) {
dev_err(&pdev->dev, "can't remap base region\n");
goto err_unmap;
@@ -5013,7 +5015,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
struct RUNTIME_9060 __iomem *ctl_addr;
- ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+ ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+ CyPCI_Zctl);
if (addr0 == NULL) {
dev_err(&pdev->dev, "can't remap ctl region\n");
goto err_reg;
@@ -5026,8 +5029,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
mailbox = (u32)readl(&ctl_addr->mail_box_0);
- addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
- CyPCI_Ze_win : CyPCI_Zwin);
+ addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+ mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
if (addr2 == NULL) {
dev_err(&pdev->dev, "can't remap base region\n");
goto err_unmap;
@@ -5159,9 +5162,9 @@ err_null:
cy_card[card_no].base_addr = NULL;
free_irq(irq, &cy_card[card_no]);
err_unmap:
- pci_iounmap(pdev, addr0);
+ iounmap(addr0);
if (addr2)
- pci_iounmap(pdev, addr2);
+ iounmap(addr2);
err_reg:
pci_release_regions(pdev);
err_dis:
@@ -5186,9 +5189,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
cy_writew(cinfo->ctl_addr + 0x68,
readw(cinfo->ctl_addr + 0x68) & ~0x0900);
- pci_iounmap(pdev, cinfo->base_addr);
+ iounmap(cinfo->base_addr);
if (cinfo->ctl_addr)
- pci_iounmap(pdev, cinfo->ctl_addr);
+ iounmap(cinfo->ctl_addr);
if (cinfo->irq
#ifndef CONFIG_CYZ_INTR
&& !IS_CYC_Z(*cinfo)
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 456e4ede049..4998b2761e8 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1376,6 +1376,7 @@ static void post_fep_init(unsigned int crd)
unsigned long flags;
u16 tseg, rseg;
+ tty_port_init(&ch->port);
ch->brdchan = bc;
ch->mailbox = gd;
INIT_WORK(&ch->tqueue, do_softint);
@@ -1510,10 +1511,6 @@ static void post_fep_init(unsigned int crd)
ch->fepstopca = 0;
ch->close_delay = 50;
- ch->port.count = 0;
- ch->port.blocked_open = 0;
- init_waitqueue_head(&ch->port.open_wait);
- init_waitqueue_head(&ch->port.close_wait);
spin_unlock_irqrestore(&epca_lock, flags);
}
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 19d3afb0e50..c6090f84a2e 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -54,8 +54,6 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch)
func_enter ();
- if (!tty) return 0;
-
port = tty->driver_data;
if (!port) return 0;
@@ -97,8 +95,6 @@ int gs_write(struct tty_struct * tty,
func_enter ();
- if (!tty) return 0;
-
port = tty->driver_data;
if (!port) return 0;
@@ -185,7 +181,6 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty)
struct gs_port *port;
func_enter ();
- if (!tty) return 0;
port = tty->driver_data;
if (!port->rd) return 0;
@@ -274,8 +269,6 @@ void gs_flush_buffer(struct tty_struct *tty)
func_enter ();
- if (!tty) return;
-
port = tty->driver_data;
if (!port) return;
@@ -296,8 +289,6 @@ void gs_flush_chars(struct tty_struct * tty)
func_enter ();
- if (!tty) return;
-
port = tty->driver_data;
if (!port) return;
@@ -321,8 +312,6 @@ void gs_stop(struct tty_struct * tty)
func_enter ();
- if (!tty) return;
-
port = tty->driver_data;
if (!port) return;
@@ -341,8 +330,6 @@ void gs_start(struct tty_struct * tty)
{
struct gs_port *port;
- if (!tty) return;
-
port = tty->driver_data;
if (!port) return;
@@ -393,8 +380,6 @@ void gs_hangup(struct tty_struct *tty)
func_enter ();
- if (!tty) return;
-
port = tty->driver_data;
tty = port->port.tty;
if (!tty)
@@ -426,8 +411,6 @@ int gs_block_til_ready(void *port_, struct file * filp)
tty = port->port.tty;
- if (!tty) return 0;
-
gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n");
/*
* If the device is in the middle of being closed, then block
@@ -523,8 +506,6 @@ void gs_close(struct tty_struct * tty, struct file * filp)
func_enter ();
- if (!tty) return;
-
port = (struct gs_port *) tty->driver_data;
if (!port) return;
@@ -621,8 +602,6 @@ void gs_set_termios (struct tty_struct * tty,
func_enter();
- if (!tty) return;
-
port = tty->driver_data;
if (!port) return;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index b3f5dbc6d88..f3cfb4c7612 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -53,6 +53,11 @@
#define HPET_RANGE_SIZE 1024 /* from HPET spec */
+
+/* WARNING -- don't get confused. These macros are never used
+ * to write the (single) counter, and rarely to read it.
+ * They're badly named; to fix, someday.
+ */
#if BITS_PER_LONG == 64
#define write_counter(V, MC) writeq(V, MC)
#define read_counter(MC) readq(MC)
@@ -77,7 +82,7 @@ static struct clocksource clocksource_hpet = {
.rating = 250,
.read = read_hpet,
.mask = CLOCKSOURCE_MASK(64),
- .mult = 0, /*to be caluclated*/
+ .mult = 0, /* to be calculated */
.shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -86,8 +91,6 @@ static struct clocksource *hpet_clocksource;
/* A lock for concurrent access by app and isr hpet activity. */
static DEFINE_SPINLOCK(hpet_lock);
-/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
-static DEFINE_SPINLOCK(hpet_task_lock);
#define HPET_DEV_NAME (7)
@@ -99,7 +102,6 @@ struct hpet_dev {
unsigned long hd_irqdata;
wait_queue_head_t hd_waitqueue;
struct fasync_struct *hd_async_queue;
- struct hpet_task *hd_task;
unsigned int hd_flags;
unsigned int hd_irq;
unsigned int hd_hdwirq;
@@ -173,11 +175,6 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
writel(isr, &devp->hd_hpet->hpet_isr);
spin_unlock(&hpet_lock);
- spin_lock(&hpet_task_lock);
- if (devp->hd_task)
- devp->hd_task->ht_func(devp->hd_task->ht_data);
- spin_unlock(&hpet_task_lock);
-
wake_up_interruptible(&devp->hd_waitqueue);
kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
@@ -185,6 +182,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
+static void hpet_timer_set_irq(struct hpet_dev *devp)
+{
+ unsigned long v;
+ int irq, gsi;
+ struct hpet_timer __iomem *timer;
+
+ spin_lock_irq(&hpet_lock);
+ if (devp->hd_hdwirq) {
+ spin_unlock_irq(&hpet_lock);
+ return;
+ }
+
+ timer = devp->hd_timer;
+
+ /* we prefer level triggered mode */
+ v = readl(&timer->hpet_config);
+ if (!(v & Tn_INT_TYPE_CNF_MASK)) {
+ v |= Tn_INT_TYPE_CNF_MASK;
+ writel(v, &timer->hpet_config);
+ }
+ spin_unlock_irq(&hpet_lock);
+
+ v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
+ Tn_INT_ROUTE_CAP_SHIFT;
+
+ /*
+ * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
+ * legacy device. In IO APIC mode, we skip all the legacy IRQS.
+ */
+ if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
+ v &= ~0xf3df;
+ else
+ v &= ~0xffff;
+
+ for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ;
+ irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) {
+
+ if (irq >= NR_IRQS) {
+ irq = HPET_MAX_IRQ;
+ break;
+ }
+
+ gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
+ ACPI_ACTIVE_LOW);
+ if (gsi > 0)
+ break;
+
+ /* FIXME: Setup interrupt source table */
+ }
+
+ if (irq < HPET_MAX_IRQ) {
+ spin_lock_irq(&hpet_lock);
+ v = readl(&timer->hpet_config);
+ v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+ writel(v, &timer->hpet_config);
+ devp->hd_hdwirq = gsi;
+ spin_unlock_irq(&hpet_lock);
+ }
+ return;
+}
+
static int hpet_open(struct inode *inode, struct file *file)
{
struct hpet_dev *devp;
@@ -199,8 +257,7 @@ static int hpet_open(struct inode *inode, struct file *file)
for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
for (i = 0; i < hpetp->hp_ntimer; i++)
- if (hpetp->hp_dev[i].hd_flags & HPET_OPEN
- || hpetp->hp_dev[i].hd_task)
+ if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
continue;
else {
devp = &hpetp->hp_dev[i];
@@ -219,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file)
spin_unlock_irq(&hpet_lock);
unlock_kernel();
+ hpet_timer_set_irq(devp);
+
return 0;
}
@@ -441,7 +500,11 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
devp->hd_irq = irq;
t = devp->hd_ireqfreq;
v = readq(&timer->hpet_config);
- g = v | Tn_INT_ENB_CNF_MASK;
+
+ /* 64-bit comparators are not yet supported through the ioctls,
+ * so force this into 32-bit mode if it supports both modes
+ */
+ g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK;
if (devp->hd_flags & HPET_PERIODIC) {
write_counter(t, &timer->hpet_compare);
@@ -451,6 +514,12 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
v |= Tn_VAL_SET_CNF_MASK;
writeq(v, &timer->hpet_config);
local_irq_save(flags);
+
+ /* NOTE: what we modify here is a hidden accumulator
+ * register supported by periodic-capable comparators.
+ * We never want to modify the (single) counter; that
+ * would affect all the comparators.
+ */
m = read_counter(&hpet->hpet_mc);
write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
} else {
@@ -604,57 +673,6 @@ static int hpet_is_known(struct hpet_data *hdp)
return 0;
}
-static inline int hpet_tpcheck(struct hpet_task *tp)
-{
- struct hpet_dev *devp;
- struct hpets *hpetp;
-
- devp = tp->ht_opaque;
-
- if (!devp)
- return -ENXIO;
-
- for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
- if (devp >= hpetp->hp_dev
- && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
- && devp->hd_hpet == hpetp->hp_hpet)
- return 0;
-
- return -ENXIO;
-}
-
-#if 0
-int hpet_unregister(struct hpet_task *tp)
-{
- struct hpet_dev *devp;
- struct hpet_timer __iomem *timer;
- int err;
-
- if ((err = hpet_tpcheck(tp)))
- return err;
-
- spin_lock_irq(&hpet_task_lock);
- spin_lock(&hpet_lock);
-
- devp = tp->ht_opaque;
- if (devp->hd_task != tp) {
- spin_unlock(&hpet_lock);
- spin_unlock_irq(&hpet_task_lock);
- return -ENXIO;
- }
-
- timer = devp->hd_timer;
- writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
- &timer->hpet_config);
- devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
- devp->hd_task = NULL;
- spin_unlock(&hpet_lock);
- spin_unlock_irq(&hpet_task_lock);
-
- return 0;
-}
-#endif /* 0 */
-
static ctl_table hpet_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
@@ -746,6 +764,7 @@ int hpet_alloc(struct hpet_data *hdp)
static struct hpets *last = NULL;
unsigned long period;
unsigned long long temp;
+ u32 remainder;
/*
* hpet_alloc can be called by platform dependent code.
@@ -809,9 +828,13 @@ int hpet_alloc(struct hpet_data *hdp)
printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
printk("\n");
- printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n",
- hpetp->hp_which, hpetp->hp_ntimer,
- cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq);
+ temp = hpetp->hp_tick_freq;
+ remainder = do_div(temp, 1000000);
+ printk(KERN_INFO
+ "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n",
+ hpetp->hp_which, hpetp->hp_ntimer,
+ cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
+ (unsigned) temp, remainder);
mcfg = readq(&hpet->hpet_config);
if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
@@ -874,8 +897,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
hdp->hd_address = ioremap(addr.minimum, addr.address_length);
if (hpet_is_known(hdp)) {
- printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
@@ -891,8 +912,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
HPET_RANGE_SIZE);
if (hpet_is_known(hdp)) {
- printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index fd64137b1ab..ec7aded0a2d 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -819,11 +819,11 @@ static int hvc_init(void)
hvc_driver = drv;
return 0;
-put_tty:
- put_tty_driver(hvc_driver);
stop_thread:
kthread_stop(hvc_task);
hvc_task = NULL;
+put_tty:
+ put_tty_driver(drv);
out:
return err;
}
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index 6b70aa66a58..538ceea5e7d 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -108,8 +108,8 @@ static int __init xen_init(void)
{
struct hvc_struct *hp;
- if (!is_running_on_xen() ||
- is_initial_xendomain() ||
+ if (!xen_pv_domain() ||
+ xen_initial_domain() ||
!xen_start_info->console.domU.evtchn)
return -ENODEV;
@@ -142,7 +142,7 @@ static void __exit xen_fini(void)
static int xen_cons_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_pv_domain())
return 0;
hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 5220f541df2..8859aeac2d2 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -736,7 +736,7 @@ static int __devexit n2rng_remove(struct of_device *op)
return 0;
}
-static struct of_device_id n2rng_match[] = {
+static const struct of_device_id n2rng_match[] = {
{
.name = "random-number-generator",
.compatible = "SUNW,n2-rng",
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
index 939618f62fe..bc397d92b49 100644
--- a/drivers/char/ip2/Makefile
+++ b/drivers/char/ip2/Makefile
@@ -4,5 +4,5 @@
obj-$(CONFIG_COMPUTONE) += ip2.o
-ip2-objs := ip2base.o ip2main.o
+ip2-objs := ip2main.o
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
index 3601017f58c..29db44de399 100644
--- a/drivers/char/ip2/i2ellis.c
+++ b/drivers/char/ip2/i2ellis.c
@@ -69,38 +69,6 @@ static DEFINE_RWLOCK(Dl_spinlock);
//=======================================================
//******************************************************************************
-// Function: iiEllisInit()
-// Parameters: None
-//
-// Returns: Nothing
-//
-// Description:
-//
-// This routine performs any required initialization of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisInit(void)
-{
-}
-
-//******************************************************************************
-// Function: iiEllisCleanup()
-// Parameters: None
-//
-// Returns: Nothing
-//
-// Description:
-//
-// This routine performs any required cleanup of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisCleanup(void)
-{
-}
-
-//******************************************************************************
// Function: iiSetAddress(pB, address, delay)
// Parameters: pB - pointer to the board structure
// address - the purported I/O address of the board
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index c88a64e527a..fb6df245601 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -511,7 +511,6 @@ typedef void (*delayFunc_t)(unsigned int);
//
// Initialization of a board & structure is in four (five!) parts:
//
-// 0) iiEllisInit() - Initialize iiEllis subsystem.
// 1) iiSetAddress() - Define the board address & delay function for a board.
// 2) iiReset() - Reset the board (provided it exists)
// -- Note you may do this to several boards --
@@ -523,7 +522,6 @@ typedef void (*delayFunc_t)(unsigned int);
// loadware. To change loadware, you must begin again with step 2, resetting
// the board again (step 1 not needed).
-static void iiEllisInit(void);
static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t );
static int iiReset(i2eBordStrPtr);
static int iiResetDelay(i2eBordStrPtr);
diff --git a/drivers/char/ip2/ip2base.c b/drivers/char/ip2/ip2base.c
deleted file mode 100644
index 8155e247c04..00000000000
--- a/drivers/char/ip2/ip2base.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// ip2.c
-// This is a dummy module to make the firmware available when needed
-// and allows it to be unloaded when not. Rumor is the __initdata
-// macro doesn't always works on all platforms so we use this kludge.
-// If not compiled as a module it just makes fip_firm avaliable then
-// __initdata should work as advertized
-//
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-
-#ifndef __init
-#define __init
-#endif
-#ifndef __initfunc
-#define __initfunc(a) a
-#endif
-#ifndef __initdata
-#define __initdata
-#endif
-
-#include "ip2types.h"
-
-int
-ip2_loadmain(int *, int *); // ref into ip2main.c
-
-/* Note: Add compiled in defaults to these arrays, not to the structure
- in ip2.h any longer. That structure WILL get overridden
- by these values, or command line values, or insmod values!!! =mhw=
-*/
-static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
-static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
-
-static int poll_only = 0;
-
-MODULE_AUTHOR("Doug McNash");
-MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
-module_param(poll_only, bool, 0);
-MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
-
-
-static int __init ip2_init(void)
-{
- if( poll_only ) {
- /* Hard lock the interrupts to zero */
- irq[0] = irq[1] = irq[2] = irq[3] = 0;
- }
-
- return ip2_loadmain(io, irq);
-}
-module_init(ip2_init);
-
-MODULE_LICENSE("GPL");
-
-#ifndef MODULE
-/******************************************************************************
- * ip2_setup:
- * str: kernel command line string
- *
- * Can't autoprobe the boards so user must specify configuration on
- * kernel command line. Sane people build it modular but the others
- * come here.
- *
- * Alternating pairs of io,irq for up to 4 boards.
- * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
- *
- * io=0 => No board
- * io=1 => PCI
- * io=2 => EISA
- * else => ISA I/O address
- *
- * irq=0 or invalid for ISA will revert to polling mode
- *
- * Any value = -1, do not overwrite compiled in value.
- *
- ******************************************************************************/
-static int __init ip2_setup(char *str)
-{
- int ints[10]; /* 4 boards, 2 parameters + 2 */
- int i, j;
-
- str = get_options (str, ARRAY_SIZE(ints), ints);
-
- for( i = 0, j = 1; i < 4; i++ ) {
- if( j > ints[0] ) {
- break;
- }
- if( ints[j] >= 0 ) {
- io[i] = ints[j];
- }
- j++;
- if( j > ints[0] ) {
- break;
- }
- if( ints[j] >= 0 ) {
- irq[i] = ints[j];
- }
- j++;
- }
- return 1;
-}
-__setup("ip2=", ip2_setup);
-#endif /* !MODULE */
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 689f9dcd3b8..6774572d375 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -150,15 +150,12 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
/*************/
/* String constants to identify ourselves */
-static char *pcName = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.14";
+static const char pcName[] = "Computone IntelliPort Plus multiport driver";
+static const char pcVersion[] = "1.2.14";
/* String constants for port names */
-static char *pcDriver_name = "ip2";
-static char *pcIpl = "ip2ipl";
-
-// cheezy kludge or genius - you decide?
-int ip2_loadmain(int *, int *);
+static const char pcDriver_name[] = "ip2";
+static const char pcIpl[] = "ip2ipl";
/***********************/
/* Function Prototypes */
@@ -240,8 +237,8 @@ static const struct file_operations ip2_ipl = {
.open = ip2_ipl_open,
};
-static unsigned long irq_counter = 0;
-static unsigned long bh_counter = 0;
+static unsigned long irq_counter;
+static unsigned long bh_counter;
// Use immediate queue to service interrupts
#define USE_IQI
@@ -252,7 +249,6 @@ static unsigned long bh_counter = 0;
*/
#define POLL_TIMEOUT (jiffies + 1)
static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
-static char TimerOn;
#ifdef IP2DEBUG_TRACE
/* Trace (debug) buffer data */
@@ -268,8 +264,8 @@ static int tracewrap;
/**********/
#if defined(MODULE) && defined(IP2DEBUG_OPEN)
-#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
- tty->name,(pCh->flags),ip2_tty_driver->refcount, \
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
+ tty->name,(pCh->flags), \
tty->count,/*GET_USE_COUNT(module)*/0,s)
#else
#define DBG_CNT(s)
@@ -287,8 +283,9 @@ static int tracewrap;
MODULE_AUTHOR("Doug McNash");
MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+MODULE_LICENSE("GPL");
-static int poll_only = 0;
+static int poll_only;
static int Eisa_irq;
static int Eisa_slot;
@@ -297,34 +294,46 @@ static int iindx;
static char rirqs[IP2_MAX_BOARDS];
static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
+/* Note: Add compiled in defaults to these arrays, not to the structure
+ in ip2.h any longer. That structure WILL get overridden
+ by these values, or command line values, or insmod values!!! =mhw=
+*/
+static int io[IP2_MAX_BOARDS];
+static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
+
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
+module_param(poll_only, bool, 0);
+MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
+
/* for sysfs class support */
static struct class *ip2_class;
-// Some functions to keep track of what irq's we have
+/* Some functions to keep track of what irqs we have */
-static int
-is_valid_irq(int irq)
+static int __init is_valid_irq(int irq)
{
int *i = Valid_Irqs;
- while ((*i != 0) && (*i != irq)) {
+ while (*i != 0 && *i != irq)
i++;
- }
- return (*i);
+
+ return *i;
}
-static void
-mark_requested_irq( char irq )
+static void __init mark_requested_irq(char irq)
{
rirqs[iindx++] = irq;
}
-#ifdef MODULE
-static int
-clear_requested_irq( char irq )
+static int __exit clear_requested_irq(char irq)
{
int i;
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
if (rirqs[i] == irq) {
rirqs[i] = 0;
return 1;
@@ -332,17 +341,15 @@ clear_requested_irq( char irq )
}
return 0;
}
-#endif
-static int
-have_requested_irq( char irq )
+static int have_requested_irq(char irq)
{
- // array init to zeros so 0 irq will not be requested as a side effect
+ /* array init to zeros so 0 irq will not be requested as a side
+ * effect */
int i;
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ for (i = 0; i < IP2_MAX_BOARDS; ++i)
if (rirqs[i] == irq)
return 1;
- }
return 0;
}
@@ -361,53 +368,45 @@ have_requested_irq( char irq )
/* handle subsequent installations of the driver. All memory allocated by the */
/* driver should be returned since it may be unloaded from memory. */
/******************************************************************************/
-#ifdef MODULE
-void __exit
-ip2_cleanup_module(void)
+static void __exit ip2_cleanup_module(void)
{
int err;
int i;
-#ifdef IP2DEBUG_INIT
- printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
-#endif
- /* Stop poll timer if we had one. */
- if ( TimerOn ) {
- del_timer ( &PollTimer );
- TimerOn = 0;
- }
+ del_timer_sync(&PollTimer);
/* Reset the boards we have. */
- for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- if ( i2BoardPtrTable[i] ) {
- iiReset( i2BoardPtrTable[i] );
- }
- }
+ for (i = 0; i < IP2_MAX_BOARDS; i++)
+ if (i2BoardPtrTable[i])
+ iiReset(i2BoardPtrTable[i]);
/* The following is done at most once, if any boards were installed. */
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- if ( i2BoardPtrTable[i] ) {
- iiResetDelay( i2BoardPtrTable[i] );
+ for (i = 0; i < IP2_MAX_BOARDS; i++) {
+ if (i2BoardPtrTable[i]) {
+ iiResetDelay(i2BoardPtrTable[i]);
/* free io addresses and Tibet */
- release_region( ip2config.addr[i], 8 );
+ release_region(ip2config.addr[i], 8);
device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
- device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+ device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
+ 4 * i + 1));
}
/* Disable and remove interrupt handler. */
- if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
- free_irq ( ip2config.irq[i], (void *)&pcName);
- clear_requested_irq( ip2config.irq[i]);
+ if (ip2config.irq[i] > 0 &&
+ have_requested_irq(ip2config.irq[i])) {
+ free_irq(ip2config.irq[i], (void *)&pcName);
+ clear_requested_irq(ip2config.irq[i]);
}
}
class_destroy(ip2_class);
- if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
- printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
- }
+ err = tty_unregister_driver(ip2_tty_driver);
+ if (err)
+ printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
+ err);
put_tty_driver(ip2_tty_driver);
unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
remove_proc_entry("ip2mem", NULL);
- // free memory
+ /* free memory */
for (i = 0; i < IP2_MAX_BOARDS; i++) {
void *pB;
#ifdef CONFIG_PCI
@@ -417,24 +416,18 @@ ip2_cleanup_module(void)
ip2config.pci_dev[i] = NULL;
}
#endif
- if ((pB = i2BoardPtrTable[i]) != 0 ) {
- kfree ( pB );
+ pB = i2BoardPtrTable[i];
+ if (pB != NULL) {
+ kfree(pB);
i2BoardPtrTable[i] = NULL;
}
- if ((DevTableMem[i]) != NULL ) {
- kfree ( DevTableMem[i] );
+ if (DevTableMem[i] != NULL) {
+ kfree(DevTableMem[i]);
DevTableMem[i] = NULL;
}
}
-
- /* Cleanup the iiEllis subsystem. */
- iiEllisCleanup();
-#ifdef IP2DEBUG_INIT
- printk (KERN_DEBUG "IP2 Unloaded\n" );
-#endif
}
module_exit(ip2_cleanup_module);
-#endif /* MODULE */
static const struct tty_operations ip2_ops = {
.open = ip2_open,
@@ -494,139 +487,168 @@ static const struct firmware *ip2_request_firmware(void)
return fw;
}
-int
-ip2_loadmain(int *iop, int *irqp)
+#ifndef MODULE
+/******************************************************************************
+ * ip2_setup:
+ * str: kernel command line string
+ *
+ * Can't autoprobe the boards so user must specify configuration on
+ * kernel command line. Sane people build it modular but the others
+ * come here.
+ *
+ * Alternating pairs of io,irq for up to 4 boards.
+ * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
+ *
+ * io=0 => No board
+ * io=1 => PCI
+ * io=2 => EISA
+ * else => ISA I/O address
+ *
+ * irq=0 or invalid for ISA will revert to polling mode
+ *
+ * Any value = -1, do not overwrite compiled in value.
+ *
+ ******************************************************************************/
+static int __init ip2_setup(char *str)
+{
+ int j, ints[10]; /* 4 boards, 2 parameters + 2 */
+ unsigned int i;
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+
+ for (i = 0, j = 1; i < 4; i++) {
+ if (j > ints[0])
+ break;
+ if (ints[j] >= 0)
+ io[i] = ints[j];
+ j++;
+ if (j > ints[0])
+ break;
+ if (ints[j] >= 0)
+ irq[i] = ints[j];
+ j++;
+ }
+ return 1;
+}
+__setup("ip2=", ip2_setup);
+#endif /* !MODULE */
+
+static int __init ip2_loadmain(void)
{
int i, j, box;
int err = 0;
- static int loaded;
i2eBordStrPtr pB = NULL;
int rc = -1;
- static struct pci_dev *pci_dev_i = NULL;
+ struct pci_dev *pdev = NULL;
const struct firmware *fw = NULL;
- ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
+ if (poll_only) {
+ /* Hard lock the interrupts to zero */
+ irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
+ }
+
+ ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
/* process command line arguments to modprobe or
insmod i.e. iop & irqp */
/* irqp and iop should ALWAYS be specified now... But we check
them individually just to be sure, anyways... */
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- if (iop) {
- ip2config.addr[i] = iop[i];
- if (irqp) {
- if( irqp[i] >= 0 ) {
- ip2config.irq[i] = irqp[i];
- } else {
- ip2config.irq[i] = 0;
- }
- // This is a little bit of a hack. If poll_only=1 on command
- // line back in ip2.c OR all IRQs on all specified boards are
- // explicitly set to 0, then drop to poll only mode and override
- // PCI or EISA interrupts. This superceeds the old hack of
- // triggering if all interrupts were zero (like da default).
- // Still a hack but less prone to random acts of terrorism.
- //
- // What we really should do, now that the IRQ default is set
- // to -1, is to use 0 as a hard coded, do not probe.
- //
- // /\/\|=mhw=|\/\/
- poll_only |= irqp[i];
- }
- }
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+ ip2config.addr[i] = io[i];
+ if (irq[i] >= 0)
+ ip2config.irq[i] = irq[i];
+ else
+ ip2config.irq[i] = 0;
+ /* This is a little bit of a hack. If poll_only=1 on command
+ line back in ip2.c OR all IRQs on all specified boards are
+ explicitly set to 0, then drop to poll only mode and override
+ PCI or EISA interrupts. This superceeds the old hack of
+ triggering if all interrupts were zero (like da default).
+ Still a hack but less prone to random acts of terrorism.
+
+ What we really should do, now that the IRQ default is set
+ to -1, is to use 0 as a hard coded, do not probe.
+
+ /\/\|=mhw=|\/\/
+ */
+ poll_only |= irq[i];
}
poll_only = !poll_only;
/* Announce our presence */
- printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
-
- // ip2 can be unloaded and reloaded for no good reason
- // we can't let that happen here or bad things happen
- // second load hoses board but not system - fixme later
- if (loaded) {
- printk( KERN_INFO "Still loaded\n" );
- return 0;
- }
- loaded++;
+ printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
if (!ip2_tty_driver)
return -ENOMEM;
- /* Initialise the iiEllis subsystem. */
- iiEllisInit();
-
- /* Initialize arrays. */
- memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
- memset( DevTable, 0, sizeof DevTable );
-
/* Initialise all the boards we can find (up to the maximum). */
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- switch ( ip2config.addr[i] ) {
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+ switch (ip2config.addr[i]) {
case 0: /* skip this slot even if card is present */
break;
default: /* ISA */
/* ISA address must be specified */
- if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
- printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
- i, ip2config.addr[i] );
+ if (ip2config.addr[i] < 0x100 ||
+ ip2config.addr[i] > 0x3f8) {
+ printk(KERN_ERR "IP2: Bad ISA board %d "
+ "address %x\n", i,
+ ip2config.addr[i]);
ip2config.addr[i] = 0;
- } else {
- ip2config.type[i] = ISA;
-
- /* Check for valid irq argument, set for polling if invalid */
- if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
- printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
- ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
- }
+ break;
+ }
+ ip2config.type[i] = ISA;
+
+ /* Check for valid irq argument, set for polling if
+ * invalid */
+ if (ip2config.irq[i] &&
+ !is_valid_irq(ip2config.irq[i])) {
+ printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
+ ip2config.irq[i]);
+ /* 0 is polling and is valid in that sense */
+ ip2config.irq[i] = 0;
}
break;
case PCI:
#ifdef CONFIG_PCI
- {
- int status;
+ {
+ u32 addr;
+ int status;
- pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
- PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
- if (pci_dev_i != NULL) {
- unsigned int addr;
-
- if (pci_enable_device(pci_dev_i)) {
- printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
- pci_name(pci_dev_i));
- break;
- }
- ip2config.type[i] = PCI;
- ip2config.pci_dev[i] = pci_dev_get(pci_dev_i);
- status =
- pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
- if ( addr & 1 ) {
- ip2config.addr[i]=(USHORT)(addr&0xfffe);
- } else {
- printk( KERN_ERR "IP2: PCI I/O address error\n");
- }
+ pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
+ PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
+ if (pdev == NULL) {
+ ip2config.addr[i] = 0;
+ printk(KERN_ERR "IP2: PCI board %d not "
+ "found\n", i);
+ break;
+ }
-// If the PCI BIOS assigned it, lets try and use it. If we
-// can't acquire it or it screws up, deal with it then.
-
-// if (!is_valid_irq(pci_irq)) {
-// printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-// pci_irq = 0;
-// }
- ip2config.irq[i] = pci_dev_i->irq;
- } else { // ann error
- ip2config.addr[i] = 0;
- printk(KERN_ERR "IP2: PCI board %d not found\n", i);
- }
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev, "can't enable device\n");
+ break;
}
+ ip2config.type[i] = PCI;
+ ip2config.pci_dev[i] = pci_dev_get(pdev);
+ status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
+ &addr);
+ if (addr & 1)
+ ip2config.addr[i] = (USHORT)(addr & 0xfffe);
+ else
+ dev_err(&pdev->dev, "I/O address error\n");
+
+ ip2config.irq[i] = pdev->irq;
+ }
#else
- printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
- printk( KERN_ERR "IP2: configured in this kernel.\n");
- printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
+ printk(KERN_ERR "IP2: PCI card specified but PCI "
+ "support not enabled.\n");
+ printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
+ "defined!\n");
#endif /* CONFIG_PCI */
break;
case EISA:
- if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
+ ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
+ if (ip2config.addr[i] != 0) {
/* Eisa_irq set as side effect, boo */
ip2config.type[i] = EISA;
}
@@ -634,31 +656,32 @@ ip2_loadmain(int *iop, int *irqp)
break;
} /* switch */
} /* for */
- if (pci_dev_i)
- pci_dev_put(pci_dev_i);
+ pci_dev_put(pdev);
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- if ( ip2config.addr[i] ) {
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+ if (ip2config.addr[i]) {
pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
if (pB) {
i2BoardPtrTable[i] = pB;
- iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
- iiReset( pB );
- } else {
- printk(KERN_ERR "IP2: board memory allocation error\n");
- }
+ iiSetAddress(pB, ip2config.addr[i],
+ ii2DelayTimer);
+ iiReset(pB);
+ } else
+ printk(KERN_ERR "IP2: board memory allocation "
+ "error\n");
}
}
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
- iiResetDelay( pB );
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+ pB = i2BoardPtrTable[i];
+ if (pB != NULL) {
+ iiResetDelay(pB);
break;
}
}
- for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
/* We don't want to request the firmware unless we have at
least one board */
- if ( i2BoardPtrTable[i] != NULL ) {
+ if (i2BoardPtrTable[i] != NULL) {
if (!fw)
fw = ip2_request_firmware();
if (!fw)
@@ -669,7 +692,7 @@ ip2_loadmain(int *iop, int *irqp)
if (fw)
release_firmware(fw);
- ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
+ ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
ip2_tty_driver->owner = THIS_MODULE;
ip2_tty_driver->name = "ttyF";
@@ -680,20 +703,23 @@ ip2_loadmain(int *iop, int *irqp)
ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
ip2_tty_driver->init_termios = tty_std_termios;
ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
- ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ip2_tty_driver, &ip2_ops);
- ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
+ ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
- /* Register the tty devices. */
- if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) {
- printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
+ err = tty_register_driver(ip2_tty_driver);
+ if (err) {
+ printk(KERN_ERR "IP2: failed to register tty driver\n");
put_tty_driver(ip2_tty_driver);
- return -EINVAL;
- } else
- /* Register the IPL driver. */
- if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
- printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
+ return err; /* leaking resources */
+ }
+
+ err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
+ if (err) {
+ printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
+ err);
} else {
/* create the sysfs class */
ip2_class = class_create(THIS_MODULE, "ip2");
@@ -705,84 +731,86 @@ ip2_loadmain(int *iop, int *irqp)
/* Register the read_procmem thing */
if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
printk(KERN_ERR "IP2: failed to register read_procmem\n");
- } else {
+ return -EIO; /* leaking resources */
+ }
- ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
- /* Register the interrupt handler or poll handler, depending upon the
- * specified interrupt.
- */
+ ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
+ /* Register the interrupt handler or poll handler, depending upon the
+ * specified interrupt.
+ */
- for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- if ( 0 == ip2config.addr[i] ) {
- continue;
- }
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+ if (ip2config.addr[i] == 0)
+ continue;
- if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
- device_create_drvdata(ip2_class, NULL,
- MKDEV(IP2_IPL_MAJOR, 4 * i),
- NULL, "ipl%d", i);
- device_create_drvdata(ip2_class, NULL,
- MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
- NULL, "stat%d", i);
-
- for ( box = 0; box < ABS_MAX_BOXES; ++box )
- {
- for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
- {
- if ( pB->i2eChannelMap[box] & (1 << j) )
- {
- tty_register_device(ip2_tty_driver,
- j + ABS_BIGGEST_BOX *
- (box+i*ABS_MAX_BOXES), NULL);
- }
- }
- }
- }
+ pB = i2BoardPtrTable[i];
+ if (pB != NULL) {
+ device_create_drvdata(ip2_class, NULL,
+ MKDEV(IP2_IPL_MAJOR, 4 * i),
+ NULL, "ipl%d", i);
+ device_create_drvdata(ip2_class, NULL,
+ MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
+ NULL, "stat%d", i);
+
+ for (box = 0; box < ABS_MAX_BOXES; box++)
+ for (j = 0; j < ABS_BIGGEST_BOX; j++)
+ if (pB->i2eChannelMap[box] & (1 << j))
+ tty_register_device(
+ ip2_tty_driver,
+ j + ABS_BIGGEST_BOX *
+ (box+i*ABS_MAX_BOXES),
+ NULL);
+ }
- if (poll_only) {
-// Poll only forces driver to only use polling and
-// to ignore the probed PCI or EISA interrupts.
- ip2config.irq[i] = CIR_POLL;
- }
- if ( ip2config.irq[i] == CIR_POLL ) {
+ if (poll_only) {
+ /* Poll only forces driver to only use polling and
+ to ignore the probed PCI or EISA interrupts. */
+ ip2config.irq[i] = CIR_POLL;
+ }
+ if (ip2config.irq[i] == CIR_POLL) {
retry:
- if (!TimerOn) {
- PollTimer.expires = POLL_TIMEOUT;
- add_timer ( &PollTimer );
- TimerOn = 1;
- printk( KERN_INFO "IP2: polling\n");
- }
- } else {
- if (have_requested_irq(ip2config.irq[i]))
- continue;
- rc = request_irq( ip2config.irq[i], ip2_interrupt,
- IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
- pcName, i2BoardPtrTable[i]);
- if (rc) {
- printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
- ip2config.irq[i] = CIR_POLL;
- printk( KERN_INFO "IP2: Polling %ld/sec.\n",
- (POLL_TIMEOUT - jiffies));
- goto retry;
- }
- mark_requested_irq(ip2config.irq[i]);
- /* Initialise the interrupt handler bottom half (aka slih). */
+ if (!timer_pending(&PollTimer)) {
+ mod_timer(&PollTimer, POLL_TIMEOUT);
+ printk(KERN_INFO "IP2: polling\n");
}
- }
- for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
- if ( i2BoardPtrTable[i] ) {
- set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
+ } else {
+ if (have_requested_irq(ip2config.irq[i]))
+ continue;
+ rc = request_irq(ip2config.irq[i], ip2_interrupt,
+ IP2_SA_FLAGS |
+ (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
+ pcName, i2BoardPtrTable[i]);
+ if (rc) {
+ printk(KERN_ERR "IP2: request_irq failed: "
+ "error %d\n", rc);
+ ip2config.irq[i] = CIR_POLL;
+ printk(KERN_INFO "IP2: Polling %ld/sec.\n",
+ (POLL_TIMEOUT - jiffies));
+ goto retry;
}
+ mark_requested_irq(ip2config.irq[i]);
+ /* Initialise the interrupt handler bottom half
+ * (aka slih). */
}
}
- ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
- goto out;
+
+ for (i = 0; i < IP2_MAX_BOARDS; ++i) {
+ if (i2BoardPtrTable[i]) {
+ /* set and enable board interrupt */
+ set_irq(i, ip2config.irq[i]);
+ }
+ }
+
+ ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
+
+ return 0;
out_chrdev:
unregister_chrdev(IP2_IPL_MAJOR, "ip2");
-out:
+ /* unregister and put tty here */
return err;
}
+module_init(ip2_loadmain);
/******************************************************************************/
/* Function: ip2_init_board() */
@@ -1199,9 +1227,8 @@ ip2_polled_interrupt(void)
{
int i;
i2eBordStrPtr pB;
- const int irq = 0;
- ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
+ ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
/* Service just the boards on the list using this irq */
for( i = 0; i < i2nBoards; ++i ) {
@@ -1210,9 +1237,8 @@ ip2_polled_interrupt(void)
// Only process those boards which match our IRQ.
// IRQ = 0 for polled boards, we won't poll "IRQ" boards
- if ( pB && (pB->i2eUsingIrq == irq) ) {
+ if (pB && pB->i2eUsingIrq == 0)
ip2_irq_work(pB);
- }
}
++irq_counter;
@@ -1250,16 +1276,12 @@ ip2_poll(unsigned long arg)
{
ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
- TimerOn = 0; // it's the truth but not checked in service
-
// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
// It will NOT poll boards handled by hard interrupts.
// The issue of queued BH interrupts is handled in ip2_interrupt().
ip2_polled_interrupt();
- PollTimer.expires = POLL_TIMEOUT;
- add_timer( &PollTimer );
- TimerOn = 1;
+ mod_timer(&PollTimer, POLL_TIMEOUT);
ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
}
@@ -2871,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
case 13:
switch ( cmd ) {
case 64: /* Driver - ip2stat */
- rc = put_user(ip2_tty_driver->refcount, pIndex++ );
+ rc = put_user(-1, pIndex++ );
rc = put_user(irq_counter, pIndex++ );
rc = put_user(bh_counter, pIndex++ );
break;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 8f7cc190b62..7d30ee1d3fc 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data)
if (retries >= 100)
goto unlock;
+ tty = tty_port_tty_get(&port->port);
+ if (tty == NULL)
+ goto put_unlock;
+
for (; count > 0; count--, port++) {
/* port not active or tx disabled to force flow control */
if (!(port->port.flags & ASYNC_INITIALIZED) ||
!(port->status & ISI_TXOK))
continue;
- tty = port->port.tty;
-
- if (tty == NULL)
- continue;
-
txcount = min_t(short, TX_SIZE, port->xmit_cnt);
if (txcount <= 0 || tty->stopped || tty->hw_stopped)
continue;
@@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data)
tty_wakeup(tty);
}
+put_unlock:
+ tty_kref_put(tty);
unlock:
spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
/* schedule another tx for hopefully in about 10ms */
@@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty == NULL) {
word_count = byte_count >> 1;
while (byte_count > 1) {
@@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
}
if (port->port.flags & ASYNC_CTS_FLOW) {
- if (port->port.tty->hw_stopped) {
+ if (tty->hw_stopped) {
if (header & ISI_CTS) {
port->port.tty->hw_stopped = 0;
/* start tx ing */
@@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
tty_wakeup(tty);
}
} else if (!(header & ISI_CTS)) {
- port->port.tty->hw_stopped = 1;
+ tty->hw_stopped = 1;
/* stop tx ing */
port->status &= ~(ISI_TXOK | ISI_CTS);
}
@@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
}
outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock);
+ tty_kref_put(tty);
return IRQ_HANDLED;
}
-static void isicom_config_port(struct isi_port *port)
+static void isicom_config_port(struct tty_struct *tty)
{
+ struct isi_port *port = tty->driver_data;
struct isi_board *card = port->card;
- struct tty_struct *tty;
unsigned long baud;
unsigned long base = card->base;
u16 channel_setup, channel = port->channel,
shift_count = card->shift_count;
unsigned char flow_ctrl;
- tty = port->port.tty;
-
- if (tty == NULL)
- return;
/* FIXME: Switch to new tty baud API */
baud = C_BAUD(tty);
if (baud & CBAUDEX) {
@@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port)
/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
if (baud < 1 || baud > 4)
- port->port.tty->termios->c_cflag &= ~CBAUDEX;
+ tty->termios->c_cflag &= ~CBAUDEX;
else
baud += 15;
}
@@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
spin_unlock_irqrestore(&bp->card_lock, flags);
}
-static int isicom_setup_port(struct isi_port *port)
+static int isicom_setup_port(struct tty_struct *tty)
{
+ struct isi_port *port = tty->driver_data;
struct isi_board *card = port->card;
unsigned long flags;
@@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port)
return -ENOMEM;
spin_lock_irqsave(&card->card_lock, flags);
- if (port->port.tty)
- clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->port.count == 1)
card->count++;
@@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port)
InterruptTheCard(card->base);
}
- isicom_config_port(port);
+ isicom_config_port(tty);
port->port.flags |= ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
@@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
port->port.count++;
tty->driver_data = port;
- port->port.tty = tty;
- error = isicom_setup_port(port);
+ tty_port_tty_set(&port->port, tty);
+ error = isicom_setup_port(tty);
if (error == 0)
error = block_til_ready(tty, filp, port);
return error;
@@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port)
struct isi_board *card = port->card;
struct tty_struct *tty;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
- if (!(port->port.flags & ASYNC_INITIALIZED))
+ if (!(port->port.flags & ASYNC_INITIALIZED)) {
+ tty_kref_put(tty);
return;
+ }
tty_port_free_xmit_buf(&port->port);
port->port.flags &= ~ASYNC_INITIALIZED;
/* 3rd October 2000 : Vinayak P Risbud */
- port->port.tty = NULL;
+ tty_port_tty_set(&port->port, NULL);
/*Fix done by Anil .S on 30-04-2001
remote login through isi port has dtr toggle problem
@@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
-static int isicom_set_serial_info(struct isi_port *port,
- struct serial_struct __user *info)
+static int isicom_set_serial_info(struct tty_struct *tty,
+ struct serial_struct __user *info)
{
+ struct isi_port *port = tty->driver_data;
struct serial_struct newinfo;
int reconfig_port;
@@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port,
if (reconfig_port) {
unsigned long flags;
spin_lock_irqsave(&port->card->card_lock, flags);
- isicom_config_port(port);
+ isicom_config_port(tty);
spin_unlock_irqrestore(&port->card->card_lock, flags);
}
unlock_kernel();
@@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
return isicom_get_serial_info(port, argp);
case TIOCSSERIAL:
- return isicom_set_serial_info(port, argp);
+ return isicom_set_serial_info(tty, argp);
default:
return -ENOIOCTLCMD;
@@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty,
return;
spin_lock_irqsave(&port->card->card_lock, flags);
- isicom_config_port(port);
+ isicom_config_port(tty);
spin_unlock_irqrestore(&port->card->card_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty)
port->port.count = 0;
port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- port->port.tty = NULL;
+ tty_port_tty_set(&port->port, NULL);
wake_up_interruptible(&port->port.open_wait);
}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 843a2afaf20..505d7a1f6b8 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -623,24 +623,25 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
static void stli_poll(unsigned long arg);
static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
-static int stli_initopen(struct stlibrd *brdp, struct stliport *portp);
+static int stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp);
static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
-static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
-static int stli_setport(struct stliport *portp);
+static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+ struct stliport *portp, struct file *filp);
+static int stli_setport(struct tty_struct *tty);
static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);
-static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
+static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
static long stli_mktiocm(unsigned long sigvalue);
static void stli_read(struct stlibrd *brdp, struct stliport *portp);
static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp);
-static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp);
+static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp);
static int stli_getbrdstats(combrd_t __user *bp);
-static int stli_getportstats(struct stliport *portp, comstats_t __user *cp);
-static int stli_portcmdstats(struct stliport *portp);
+static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp);
+static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp);
static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp);
static int stli_getportstruct(struct stliport __user *arg);
static int stli_getbrdstruct(struct stlibrd __user *arg);
@@ -731,12 +732,16 @@ static void stli_cleanup_ports(struct stlibrd *brdp)
{
struct stliport *portp;
unsigned int j;
+ struct tty_struct *tty;
for (j = 0; j < STL_MAXPORTS; j++) {
portp = brdp->ports[j];
if (portp != NULL) {
- if (portp->port.tty != NULL)
- tty_hangup(portp->port.tty);
+ tty = tty_port_tty_get(&portp->port);
+ if (tty != NULL) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
kfree(portp);
}
}
@@ -824,7 +829,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
* requires several commands to the board we will need to wait for any
* other open that is already initializing the port.
*/
- portp->port.tty = tty;
+ tty_port_tty_set(&portp->port, tty);
tty->driver_data = portp;
portp->port.count++;
@@ -835,7 +840,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
set_bit(ST_INITIALIZING, &portp->state);
- if ((rc = stli_initopen(brdp, portp)) >= 0) {
+ if ((rc = stli_initopen(tty, brdp, portp)) >= 0) {
portp->port.flags |= ASYNC_INITIALIZED;
clear_bit(TTY_IO_ERROR, &tty->flags);
}
@@ -864,7 +869,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
* then also we might have to wait for carrier.
*/
if (!(filp->f_flags & O_NONBLOCK)) {
- if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
+ if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0)
return rc;
}
portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -930,7 +935,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
stli_flushbuffer(tty);
tty->closing = 0;
- portp->port.tty = NULL;
+ tty_port_tty_set(&portp->port, NULL);
if (portp->openwaitcnt) {
if (portp->close_delay)
@@ -952,9 +957,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
* this still all happens pretty quickly.
*/
-static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
+static int stli_initopen(struct tty_struct *tty,
+ struct stlibrd *brdp, struct stliport *portp)
{
- struct tty_struct *tty;
asynotify_t nt;
asyport_t aport;
int rc;
@@ -969,10 +974,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
sizeof(asynotify_t), 0)) < 0)
return rc;
- tty = portp->port.tty;
- if (tty == NULL)
- return -ENODEV;
- stli_mkasyport(portp, &aport, tty->termios);
+ stli_mkasyport(tty, portp, &aport, tty->termios);
if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
sizeof(asyport_t), 0)) < 0)
return rc;
@@ -1161,22 +1163,21 @@ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned l
* waiting for the command to complete - so must have user context.
*/
-static int stli_setport(struct stliport *portp)
+static int stli_setport(struct tty_struct *tty)
{
+ struct stliport *portp = tty->driver_data;
struct stlibrd *brdp;
asyport_t aport;
if (portp == NULL)
return -ENODEV;
- if (portp->port.tty == NULL)
- return -ENODEV;
if (portp->brdnr >= stli_nrbrds)
return -ENODEV;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
return -ENODEV;
- stli_mkasyport(portp, &aport, portp->port.tty->termios);
+ stli_mkasyport(tty, portp, &aport, tty->termios);
return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
}
@@ -1187,7 +1188,8 @@ static int stli_setport(struct stliport *portp)
* maybe because if we are clocal then we don't need to wait...
*/
-static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp)
+static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp,
+ struct stliport *portp, struct file *filp)
{
unsigned long flags;
int rc, doclocal;
@@ -1195,7 +1197,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct
rc = 0;
doclocal = 0;
- if (portp->port.tty->termios->c_cflag & CLOCAL)
+ if (tty->termios->c_cflag & CLOCAL)
doclocal++;
spin_lock_irqsave(&stli_lock, flags);
@@ -1373,8 +1375,6 @@ static void stli_flushchars(struct tty_struct *tty)
stli_txcookrealsize = 0;
stli_txcooktty = NULL;
- if (tty == NULL)
- return;
if (cooktty == NULL)
return;
if (tty != cooktty)
@@ -1572,10 +1572,11 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s
* just quietly ignore any requests to change irq, etc.
*/
-static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp)
+static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
{
struct serial_struct sio;
int rc;
+ struct stliport *portp = tty->driver_data;
if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
return -EFAULT;
@@ -1594,7 +1595,7 @@ static int stli_setserial(struct stliport *portp, struct serial_struct __user *s
portp->closing_wait = sio.closing_wait;
portp->custom_divisor = sio.custom_divisor;
- if ((rc = stli_setport(portp)) < 0)
+ if ((rc = stli_setport(tty)) < 0)
return rc;
return 0;
}
@@ -1685,17 +1686,17 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
rc = stli_getserial(portp, argp);
break;
case TIOCSSERIAL:
- rc = stli_setserial(portp, argp);
+ rc = stli_setserial(tty, argp);
break;
case STL_GETPFLAG:
rc = put_user(portp->pflag, (unsigned __user *)argp);
break;
case STL_SETPFLAG:
if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0)
- stli_setport(portp);
+ stli_setport(tty);
break;
case COM_GETPORTSTATS:
- rc = stli_getportstats(portp, argp);
+ rc = stli_getportstats(tty, portp, argp);
break;
case COM_CLRPORTSTATS:
rc = stli_clrportstats(portp, argp);
@@ -1729,8 +1730,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
struct ktermios *tiosp;
asyport_t aport;
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1742,7 +1741,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
tiosp = tty->termios;
- stli_mkasyport(portp, &aport, tiosp);
+ stli_mkasyport(tty, portp, &aport, tiosp);
stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1);
stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
@@ -1854,7 +1853,7 @@ static void stli_hangup(struct tty_struct *tty)
clear_bit(ST_TXBUSY, &portp->state);
clear_bit(ST_RXSTOP, &portp->state);
set_bit(TTY_IO_ERROR, &tty->flags);
- portp->port.tty = NULL;
+ tty_port_tty_set(&portp->port, NULL);
portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
portp->port.count = 0;
spin_unlock_irqrestore(&stli_lock, flags);
@@ -1935,8 +1934,6 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
struct stliport *portp;
unsigned long tend;
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1998,7 +1995,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn
char *sp, *uart;
int rc, cnt;
- rc = stli_portcmdstats(portp);
+ rc = stli_portcmdstats(NULL, portp);
uart = "UNKNOWN";
if (brdp->state & BST_STARTED) {
@@ -2188,7 +2185,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)
if (test_bit(ST_RXSTOP, &portp->state))
return;
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
if (tty == NULL)
return;
@@ -2230,6 +2227,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp)
set_bit(ST_RXING, &portp->state);
tty_schedule_flip(tty);
+ tty_kref_put(tty);
}
/*****************************************************************************/
@@ -2362,7 +2360,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
if (ap->notify) {
nt = ap->changed;
ap->notify = 0;
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
if (nt.signal & SG_DCD) {
oldsigs = portp->sigs;
@@ -2399,6 +2397,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
tty_schedule_flip(tty);
}
}
+ tty_kref_put(tty);
if (nt.data & DT_RXBUSY) {
donerx++;
@@ -2535,14 +2534,15 @@ static void stli_poll(unsigned long arg)
* the slave.
*/
-static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp)
+static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp,
+ asyport_t *pp, struct ktermios *tiosp)
{
memset(pp, 0, sizeof(asyport_t));
/*
* Start of by setting the baud, char size, parity and stop bit info.
*/
- pp->baudout = tty_get_baud_rate(portp->port.tty);
+ pp->baudout = tty_get_baud_rate(tty);
if ((tiosp->c_cflag & CBAUD) == B38400) {
if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
pp->baudout = 57600;
@@ -2695,7 +2695,7 @@ static int stli_initports(struct stlibrd *brdp)
printk("STALLION: failed to allocate port structure\n");
continue;
}
-
+ tty_port_init(&portp->port);
portp->magic = STLI_PORTMAGIC;
portp->portnr = i;
portp->brdnr = brdp->brdnr;
@@ -4220,7 +4220,7 @@ static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
* what port to get stats for (used through board control device).
*/
-static int stli_portcmdstats(struct stliport *portp)
+static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp)
{
unsigned long flags;
struct stlibrd *brdp;
@@ -4249,15 +4249,15 @@ static int stli_portcmdstats(struct stliport *portp)
stli_comstats.flags = portp->port.flags;
spin_lock_irqsave(&brd_lock, flags);
- if (portp->port.tty != NULL) {
- if (portp->port.tty->driver_data == portp) {
- stli_comstats.ttystate = portp->port.tty->flags;
+ if (tty != NULL) {
+ if (portp->port.tty == tty) {
+ stli_comstats.ttystate = tty->flags;
stli_comstats.rxbuffered = -1;
- if (portp->port.tty->termios != NULL) {
- stli_comstats.cflags = portp->port.tty->termios->c_cflag;
- stli_comstats.iflags = portp->port.tty->termios->c_iflag;
- stli_comstats.oflags = portp->port.tty->termios->c_oflag;
- stli_comstats.lflags = portp->port.tty->termios->c_lflag;
+ if (tty->termios != NULL) {
+ stli_comstats.cflags = tty->termios->c_cflag;
+ stli_comstats.iflags = tty->termios->c_iflag;
+ stli_comstats.oflags = tty->termios->c_oflag;
+ stli_comstats.lflags = tty->termios->c_lflag;
}
}
}
@@ -4294,7 +4294,8 @@ static int stli_portcmdstats(struct stliport *portp)
* what port to get stats for (used through board control device).
*/
-static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
+static int stli_getportstats(struct tty_struct *tty, struct stliport *portp,
+ comstats_t __user *cp)
{
struct stlibrd *brdp;
int rc;
@@ -4312,7 +4313,7 @@ static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
if (!brdp)
return -ENODEV;
- if ((rc = stli_portcmdstats(portp)) < 0)
+ if ((rc = stli_portcmdstats(tty, portp)) < 0)
return rc;
return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ?
@@ -4427,7 +4428,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
switch (cmd) {
case COM_GETPORTSTATS:
- rc = stli_getportstats(NULL, argp);
+ rc = stli_getportstats(NULL, NULL, argp);
done++;
break;
case COM_CLRPORTSTATS:
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index d3d7864e0c1..5df4003ad87 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
static void moxa_poll(unsigned long);
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_shut_down(struct moxa_port *);
+static void moxa_shut_down(struct tty_struct *);
/*
* moxa board interface functions:
*/
@@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int);
static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
static int MoxaPortLineStatus(struct moxa_port *);
static void MoxaPortFlushData(struct moxa_port *, int);
-static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
static int MoxaPortReadData(struct moxa_port *);
static int MoxaPortTxQueue(struct moxa_port *);
static int MoxaPortRxQueue(struct moxa_port *);
@@ -332,6 +332,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
for (i = 0; i < MAX_BOARDS; i++) {
p = moxa_boards[i].ports;
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+ struct tty_struct *ttyp;
memset(&tmp, 0, sizeof(tmp));
if (!moxa_boards[i].ready)
goto copy;
@@ -344,10 +345,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
if (status & 4)
tmp.dcd = 1;
- if (!p->port.tty || !p->port.tty->termios)
+ ttyp = tty_port_tty_get(&p->port);
+ if (!ttyp || !ttyp->termios)
tmp.cflag = p->cflag;
else
- tmp.cflag = p->port.tty->termios->c_cflag;
+ tmp.cflag = ttyp->termios->c_cflag;
+ tty_kref_put(tty);
copy:
if (copy_to_user(argm, &tmp, sizeof(tmp))) {
mutex_unlock(&moxa_openlock);
@@ -880,8 +883,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
/* pci hot-un-plug support */
for (a = 0; a < brd->numPorts; a++)
- if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
- tty_hangup(brd->ports[a].port.tty);
+ if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
+ struct tty_struct *tty = tty_port_tty_get(
+ &brd->ports[a].port);
+ if (tty) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
+ }
while (1) {
opened = 0;
for (a = 0; a < brd->numPorts; a++)
@@ -1096,13 +1105,14 @@ static void __exit moxa_exit(void)
module_init(moxa_init);
module_exit(moxa_exit);
-static void moxa_close_port(struct moxa_port *ch)
+static void moxa_close_port(struct tty_struct *tty)
{
- moxa_shut_down(ch);
+ struct moxa_port *ch = tty->driver_data;
+ moxa_shut_down(tty);
MoxaPortFlushData(ch, 2);
ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- ch->port.tty->driver_data = NULL;
- ch->port.tty = NULL;
+ tty->driver_data = NULL;
+ tty_port_tty_set(&ch->port, NULL);
}
static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1161,7 +1171,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
ch->port.count++;
tty->driver_data = ch;
- ch->port.tty = tty;
+ tty_port_tty_set(&ch->port, tty);
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, tty->termios);
@@ -1179,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
if (retval) {
if (ch->port.count) /* 0 means already hung up... */
if (--ch->port.count == 0)
- moxa_close_port(ch);
+ moxa_close_port(tty);
} else
ch->port.flags |= ASYNC_NORMAL_ACTIVE;
mutex_unlock(&moxa_openlock);
@@ -1219,7 +1229,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
}
- moxa_close_port(ch);
+ moxa_close_port(tty);
unlock:
mutex_unlock(&moxa_openlock);
}
@@ -1234,7 +1244,7 @@ static int moxa_write(struct tty_struct *tty,
return 0;
spin_lock_bh(&moxa_lock);
- len = MoxaPortWriteData(ch, buf, count);
+ len = MoxaPortWriteData(tty, buf, count);
spin_unlock_bh(&moxa_lock);
ch->statusflags |= LOWWAIT;
@@ -1409,7 +1419,7 @@ static void moxa_hangup(struct tty_struct *tty)
return;
}
ch->port.count = 0;
- moxa_close_port(ch);
+ moxa_close_port(tty);
mutex_unlock(&moxa_openlock);
wake_up_interruptible(&ch->port.open_wait);
@@ -1417,11 +1427,14 @@ static void moxa_hangup(struct tty_struct *tty)
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
{
+ struct tty_struct *tty;
dcd = !!dcd;
- if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) {
- if (!dcd)
- tty_hangup(p->port.tty);
+ if (dcd != p->DCDState) {
+ tty = tty_port_tty_get(&p->port);
+ if (tty && C_CLOCAL(tty) && !dcd)
+ tty_hangup(tty);
+ tty_kref_put(tty);
}
p->DCDState = dcd;
}
@@ -1429,7 +1442,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
u16 __iomem *ip)
{
- struct tty_struct *tty = p->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&p->port);
void __iomem *ofsAddr;
unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
u16 intr;
@@ -1476,6 +1489,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
tty_insert_flip_char(tty, 0, TTY_BREAK);
tty_schedule_flip(tty);
}
+ tty_kref_put(tty);
if (intr & IntrLine)
moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
@@ -1560,9 +1574,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty)
spin_unlock_bh(&moxa_lock);
}
-static void moxa_shut_down(struct moxa_port *ch)
+static void moxa_shut_down(struct tty_struct *tty)
{
- struct tty_struct *tp = ch->port.tty;
+ struct moxa_port *ch = tty->driver_data;
if (!(ch->port.flags & ASYNC_INITIALIZED))
return;
@@ -1572,7 +1586,7 @@ static void moxa_shut_down(struct moxa_port *ch)
/*
* If we're a modem control device and HUPCL is on, drop RTS & DTR.
*/
- if (C_HUPCL(tp))
+ if (C_HUPCL(tty))
MoxaPortLineCtrl(ch, 0, 0);
spin_lock_bh(&moxa_lock);
@@ -1953,9 +1967,10 @@ static int MoxaPortLineStatus(struct moxa_port *port)
return val;
}
-static int MoxaPortWriteData(struct moxa_port *port,
+static int MoxaPortWriteData(struct tty_struct *tty,
const unsigned char *buffer, int len)
{
+ struct moxa_port *port = tty->driver_data;
void __iomem *baseAddr, *ofsAddr, *ofs;
unsigned int c, total;
u16 head, tail, tx_mask, spage, epage;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index b638403e8e9..8beef50f95a 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -610,15 +610,13 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
-static int mxser_set_baud(struct mxser_port *info, long newspd)
+static int mxser_set_baud(struct tty_struct *tty, long newspd)
{
+ struct mxser_port *info = tty->driver_data;
int quot = 0, baud;
unsigned char cval;
- if (!info->port.tty || !info->port.tty->termios)
- return -1;
-
- if (!(info->ioaddr))
+ if (!info->ioaddr)
return -1;
if (newspd > info->max_baud)
@@ -626,13 +624,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
if (newspd == 134) {
quot = 2 * info->baud_base / 269;
- tty_encode_baud_rate(info->port.tty, 134, 134);
+ tty_encode_baud_rate(tty, 134, 134);
} else if (newspd) {
quot = info->baud_base / newspd;
if (quot == 0)
quot = 1;
baud = info->baud_base/quot;
- tty_encode_baud_rate(info->port.tty, baud, baud);
+ tty_encode_baud_rate(tty, baud, baud);
} else {
quot = 0;
}
@@ -658,7 +656,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
#ifdef BOTHER
- if (C_BAUD(info->port.tty) == BOTHER) {
+ if (C_BAUD(tty) == BOTHER) {
quot = info->baud_base % newspd;
quot *= 8;
if (quot % newspd > newspd / 2) {
@@ -679,21 +677,20 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static int mxser_change_speed(struct mxser_port *info,
- struct ktermios *old_termios)
+static int mxser_change_speed(struct tty_struct *tty,
+ struct ktermios *old_termios)
{
+ struct mxser_port *info = tty->driver_data;
unsigned cflag, cval, fcr;
int ret = 0;
unsigned char status;
- if (!info->port.tty || !info->port.tty->termios)
- return ret;
- cflag = info->port.tty->termios->c_cflag;
- if (!(info->ioaddr))
+ cflag = tty->termios->c_cflag;
+ if (!info->ioaddr)
return ret;
- if (mxser_set_baud_method[info->port.tty->index] == 0)
- mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
+ if (mxser_set_baud_method[tty->index] == 0)
+ mxser_set_baud(tty, tty_get_baud_rate(tty));
/* byte size and parity */
switch (cflag & CSIZE) {
@@ -762,9 +759,9 @@ static int mxser_change_speed(struct mxser_port *info,
info->MCR |= UART_MCR_AFE;
} else {
status = inb(info->ioaddr + UART_MSR);
- if (info->port.tty->hw_stopped) {
+ if (tty->hw_stopped) {
if (status & UART_MSR_CTS) {
- info->port.tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
if (info->type != PORT_16550A &&
!info->board->chip_flag) {
outb(info->IER & ~UART_IER_THRI,
@@ -774,11 +771,11 @@ static int mxser_change_speed(struct mxser_port *info,
outb(info->IER, info->ioaddr +
UART_IER);
}
- tty_wakeup(info->port.tty);
+ tty_wakeup(tty);
}
} else {
if (!(status & UART_MSR_CTS)) {
- info->port.tty->hw_stopped = 1;
+ tty->hw_stopped = 1;
if ((info->type != PORT_16550A) &&
(!info->board->chip_flag)) {
info->IER &= ~UART_IER_THRI;
@@ -804,21 +801,21 @@ static int mxser_change_speed(struct mxser_port *info,
* Set up parity check flag
*/
info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (I_INPCK(info->port.tty))
+ if (I_INPCK(tty))
info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+ if (I_BRKINT(tty) || I_PARMRK(tty))
info->read_status_mask |= UART_LSR_BI;
info->ignore_status_mask = 0;
- if (I_IGNBRK(info->port.tty)) {
+ if (I_IGNBRK(tty)) {
info->ignore_status_mask |= UART_LSR_BI;
info->read_status_mask |= UART_LSR_BI;
/*
* If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
- if (I_IGNPAR(info->port.tty)) {
+ if (I_IGNPAR(tty)) {
info->ignore_status_mask |=
UART_LSR_OE |
UART_LSR_PE |
@@ -830,16 +827,16 @@ static int mxser_change_speed(struct mxser_port *info,
}
}
if (info->board->chip_flag) {
- mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
- mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
- if (I_IXON(info->port.tty)) {
+ mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
+ mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
+ if (I_IXON(tty)) {
mxser_enable_must_rx_software_flow_control(
info->ioaddr);
} else {
mxser_disable_must_rx_software_flow_control(
info->ioaddr);
}
- if (I_IXOFF(info->port.tty)) {
+ if (I_IXOFF(tty)) {
mxser_enable_must_tx_software_flow_control(
info->ioaddr);
} else {
@@ -855,7 +852,8 @@ static int mxser_change_speed(struct mxser_port *info,
return ret;
}
-static void mxser_check_modem_status(struct mxser_port *port, int status)
+static void mxser_check_modem_status(struct tty_struct *tty,
+ struct mxser_port *port, int status)
{
/* update input line counters */
if (status & UART_MSR_TERI)
@@ -874,10 +872,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
wake_up_interruptible(&port->port.open_wait);
}
+ tty = tty_port_tty_get(&port->port);
if (port->port.flags & ASYNC_CTS_FLOW) {
- if (port->port.tty->hw_stopped) {
+ if (tty->hw_stopped) {
if (status & UART_MSR_CTS) {
- port->port.tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
if ((port->type != PORT_16550A) &&
(!port->board->chip_flag)) {
@@ -887,11 +886,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
outb(port->IER, port->ioaddr +
UART_IER);
}
- tty_wakeup(port->port.tty);
+ tty_wakeup(tty);
}
} else {
if (!(status & UART_MSR_CTS)) {
- port->port.tty->hw_stopped = 1;
+ tty->hw_stopped = 1;
if (port->type != PORT_16550A &&
!port->board->chip_flag) {
port->IER &= ~UART_IER_THRI;
@@ -903,8 +902,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
}
}
-static int mxser_startup(struct mxser_port *info)
+static int mxser_startup(struct tty_struct *tty)
{
+ struct mxser_port *info = tty->driver_data;
unsigned long page;
unsigned long flags;
@@ -921,8 +921,7 @@ static int mxser_startup(struct mxser_port *info)
}
if (!info->ioaddr || !info->type) {
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ set_bit(TTY_IO_ERROR, &tty->flags);
free_page(page);
spin_unlock_irqrestore(&info->slock, flags);
return 0;
@@ -952,8 +951,8 @@ static int mxser_startup(struct mxser_port *info)
if (inb(info->ioaddr + UART_LSR) == 0xff) {
spin_unlock_irqrestore(&info->slock, flags);
if (capable(CAP_SYS_ADMIN)) {
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
return 0;
} else
return -ENODEV;
@@ -991,14 +990,13 @@ static int mxser_startup(struct mxser_port *info)
(void) inb(info->ioaddr + UART_IIR);
(void) inb(info->ioaddr + UART_MSR);
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ clear_bit(TTY_IO_ERROR, &tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
/*
* and set the speed of the serial port
*/
- mxser_change_speed(info, NULL);
+ mxser_change_speed(tty, NULL);
info->port.flags |= ASYNC_INITIALIZED;
spin_unlock_irqrestore(&info->slock, flags);
@@ -1009,8 +1007,9 @@ static int mxser_startup(struct mxser_port *info)
* This routine will shutdown a serial port; interrupts maybe disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void mxser_shutdown(struct mxser_port *info)
+static void mxser_shutdown(struct tty_struct *tty)
{
+ struct mxser_port *info = tty->driver_data;
unsigned long flags;
if (!(info->port.flags & ASYNC_INITIALIZED))
@@ -1035,7 +1034,7 @@ static void mxser_shutdown(struct mxser_port *info)
info->IER = 0;
outb(0x00, info->ioaddr + UART_IER);
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
+ if (tty->termios->c_cflag & HUPCL)
info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
outb(info->MCR, info->ioaddr + UART_MCR);
@@ -1051,8 +1050,7 @@ static void mxser_shutdown(struct mxser_port *info)
/* read data port to reset things */
(void) inb(info->ioaddr + UART_RX);
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ set_bit(TTY_IO_ERROR, &tty->flags);
info->port.flags &= ~ASYNC_INITIALIZED;
@@ -1084,14 +1082,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
tty->driver_data = info;
- info->port.tty = tty;
+ tty_port_tty_set(&info->port, tty);
/*
* Start up serial port
*/
spin_lock_irqsave(&info->slock, flags);
info->port.count++;
spin_unlock_irqrestore(&info->slock, flags);
- retval = mxser_startup(info);
+ retval = mxser_startup(tty);
if (retval)
return retval;
@@ -1209,13 +1207,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
break;
}
}
- mxser_shutdown(info);
+ mxser_shutdown(tty);
mxser_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
- info->port.tty = NULL;
+ tty_port_tty_set(&info->port, NULL);
if (info->port.blocked_open) {
if (info->port.close_delay)
schedule_timeout_interruptible(info->port.close_delay);
@@ -1337,12 +1335,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
* friends of mxser_ioctl()
* ------------------------------------------------------------
*/
-static int mxser_get_serial_info(struct mxser_port *info,
+static int mxser_get_serial_info(struct tty_struct *tty,
struct serial_struct __user *retinfo)
{
+ struct mxser_port *info = tty->driver_data;
struct serial_struct tmp = {
.type = info->type,
- .line = info->port.tty->index,
+ .line = tty->index,
.port = info->ioaddr,
.irq = info->board->irq,
.flags = info->port.flags,
@@ -1357,9 +1356,10 @@ static int mxser_get_serial_info(struct mxser_port *info,
return 0;
}
-static int mxser_set_serial_info(struct mxser_port *info,
+static int mxser_set_serial_info(struct tty_struct *tty,
struct serial_struct __user *new_info)
{
+ struct mxser_port *info = tty->driver_data;
struct serial_struct new_serial;
speed_t baud;
unsigned long sl_flags;
@@ -1393,14 +1393,14 @@ static int mxser_set_serial_info(struct mxser_port *info,
(new_serial.flags & ASYNC_FLAGS));
info->port.close_delay = new_serial.close_delay * HZ / 100;
info->port.closing_wait = new_serial.closing_wait * HZ / 100;
- info->port.tty->low_latency =
- (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
+ ? 1 : 0;
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
(new_serial.baud_base != info->baud_base ||
new_serial.custom_divisor !=
info->custom_divisor)) {
baud = new_serial.baud_base / new_serial.custom_divisor;
- tty_encode_baud_rate(info->port.tty, baud, baud);
+ tty_encode_baud_rate(tty, baud, baud);
}
}
@@ -1411,11 +1411,11 @@ static int mxser_set_serial_info(struct mxser_port *info,
if (info->port.flags & ASYNC_INITIALIZED) {
if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
spin_lock_irqsave(&info->slock, sl_flags);
- mxser_change_speed(info, NULL);
+ mxser_change_speed(tty, NULL);
spin_unlock_irqrestore(&info->slock, sl_flags);
}
} else
- retval = mxser_startup(info);
+ retval = mxser_startup(tty);
return retval;
}
@@ -1461,7 +1461,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
spin_lock_irqsave(&info->slock, flags);
status = inb(info->ioaddr + UART_MSR);
if (status & UART_MSR_ANY_DELTA)
- mxser_check_modem_status(info, status);
+ mxser_check_modem_status(tty, info, status);
spin_unlock_irqrestore(&info->slock, flags);
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
@@ -1606,6 +1606,7 @@ static int __init mxser_read_register(int port, unsigned short *regs)
static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
{
struct mxser_port *port;
+ struct tty_struct *tty;
int result, status;
unsigned int i, j;
int ret = 0;
@@ -1643,12 +1644,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (!port->ioaddr)
goto copy;
+
+ tty = tty_port_tty_get(&port->port);
- if (!port->port.tty || !port->port.tty->termios)
+ if (!tty || !tty->termios)
ms.cflag = port->normal_termios.c_cflag;
else
- ms.cflag = port->port.tty->termios->c_cflag;
-
+ ms.cflag = tty->termios->c_cflag;
+ tty_kref_put(tty);
status = inb(port->ioaddr + UART_MSR);
if (status & UART_MSR_DCD)
ms.dcd = 1;
@@ -1704,15 +1707,18 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
me->up_txcnt[p] = port->mon_data.up_txcnt;
me->modem_status[p] =
port->mon_data.modem_status;
- me->baudrate[p] = tty_get_baud_rate(port->port.tty);
+ tty = tty_port_tty_get(&port->port);
- if (!port->port.tty || !port->port.tty->termios) {
+ if (!tty || !tty->termios) {
cflag = port->normal_termios.c_cflag;
iflag = port->normal_termios.c_iflag;
+ me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
} else {
- cflag = port->port.tty->termios->c_cflag;
- iflag = port->port.tty->termios->c_iflag;
+ cflag = tty->termios->c_cflag;
+ iflag = tty->termios->c_iflag;
+ me->baudrate[p] = tty_get_baud_rate(tty);
}
+ tty_kref_put(tty);
me->databits[p] = cflag & CSIZE;
me->stopbits[p] = cflag & CSTOPB;
@@ -1822,12 +1828,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
switch (cmd) {
case TIOCGSERIAL:
lock_kernel();
- retval = mxser_get_serial_info(info, argp);
+ retval = mxser_get_serial_info(tty, argp);
unlock_kernel();
return retval;
case TIOCSSERIAL:
lock_kernel();
- retval = mxser_set_serial_info(info, argp);
+ retval = mxser_set_serial_info(tty, argp);
unlock_kernel();
return retval;
case TIOCSERGETLSR: /* Get line status register */
@@ -1896,7 +1902,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
lock_kernel();
status = mxser_get_msr(info->ioaddr, 1, tty->index);
- mxser_check_modem_status(info, status);
+ mxser_check_modem_status(tty, info, status);
mcr = inb(info->ioaddr + UART_MCR);
if (mcr & MOXA_MUST_MCR_XON_FLAG)
@@ -1909,7 +1915,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
else
info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
- if (info->port.tty->hw_stopped)
+ if (tty->hw_stopped)
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
else
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
@@ -1958,7 +1964,7 @@ static void mxser_stoprx(struct tty_struct *tty)
}
}
- if (info->port.tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios->c_cflag & CRTSCTS) {
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1995,7 +2001,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
}
}
- if (info->port.tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios->c_cflag & CRTSCTS) {
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -2040,7 +2046,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
- mxser_change_speed(info, old_termios);
+ mxser_change_speed(tty, old_termios);
spin_unlock_irqrestore(&info->slock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
@@ -2138,10 +2144,10 @@ static void mxser_hangup(struct tty_struct *tty)
struct mxser_port *info = tty->driver_data;
mxser_flush_buffer(tty);
- mxser_shutdown(info);
+ mxser_shutdown(tty);
info->port.count = 0;
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
- info->port.tty = NULL;
+ tty_port_tty_set(&info->port, NULL);
wake_up_interruptible(&info->port.open_wait);
}
@@ -2164,9 +2170,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state)
return 0;
}
-static void mxser_receive_chars(struct mxser_port *port, int *status)
+static void mxser_receive_chars(struct tty_struct *tty,
+ struct mxser_port *port, int *status)
{
- struct tty_struct *tty = port->port.tty;
unsigned char ch, gdl;
int ignored = 0;
int cnt = 0;
@@ -2174,9 +2180,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
int max = 256;
recv_room = tty->receive_room;
- if ((recv_room == 0) && (!port->ldisc_stop_rx))
+ if (recv_room == 0 && !port->ldisc_stop_rx)
mxser_stoprx(tty);
-
if (port->board->chip_flag != MOXA_OTHER_UART) {
if (*status & UART_LSR_SPECIAL)
@@ -2253,7 +2258,7 @@ intr_old:
} while (*status & UART_LSR_DR);
end_intr:
- mxvar_log.rxcnt[port->port.tty->index] += cnt;
+ mxvar_log.rxcnt[tty->index] += cnt;
port->mon_data.rxcnt += cnt;
port->mon_data.up_rxcnt += cnt;
@@ -2267,14 +2272,14 @@ end_intr:
spin_lock(&port->slock);
}
-static void mxser_transmit_chars(struct mxser_port *port)
+static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
{
int count, cnt;
if (port->x_char) {
outb(port->x_char, port->ioaddr + UART_TX);
port->x_char = 0;
- mxvar_log.txcnt[port->port.tty->index]++;
+ mxvar_log.txcnt[tty->index]++;
port->mon_data.txcnt++;
port->mon_data.up_txcnt++;
port->icount.tx++;
@@ -2284,8 +2289,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
if (port->port.xmit_buf == NULL)
return;
- if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
- (port->port.tty->hw_stopped &&
+ if (port->xmit_cnt <= 0 || tty->stopped ||
+ (tty->hw_stopped &&
(port->type != PORT_16550A) &&
(!port->board->chip_flag))) {
port->IER &= ~UART_IER_THRI;
@@ -2302,14 +2307,14 @@ static void mxser_transmit_chars(struct mxser_port *port)
if (--port->xmit_cnt <= 0)
break;
} while (--count > 0);
- mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
+ mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
port->mon_data.txcnt += (cnt - port->xmit_cnt);
port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
port->icount.tx += (cnt - port->xmit_cnt);
- if (port->xmit_cnt < WAKEUP_CHARS)
- tty_wakeup(port->port.tty);
+ if (port->xmit_cnt < WAKEUP_CHARS && tty)
+ tty_wakeup(tty);
if (port->xmit_cnt <= 0) {
port->IER &= ~UART_IER_THRI;
@@ -2328,6 +2333,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
int max, irqbits, bits, msr;
unsigned int int_cnt, pass_counter = 0;
int handled = IRQ_NONE;
+ struct tty_struct *tty;
for (i = 0; i < MXSER_BOARDS; i++)
if (dev_id == &mxser_boards[i]) {
@@ -2360,13 +2366,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
if (iir & UART_IIR_NO_INT)
break;
iir &= MOXA_MUST_IIR_MASK;
- if (!port->port.tty ||
+ tty = tty_port_tty_get(&port->port);
+ if (!tty ||
(port->port.flags & ASYNC_CLOSING) ||
!(port->port.flags &
ASYNC_INITIALIZED)) {
status = inb(port->ioaddr + UART_LSR);
outb(0x27, port->ioaddr + UART_FCR);
inb(port->ioaddr + UART_MSR);
+ tty_kref_put(tty);
break;
}
@@ -2387,27 +2395,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
iir == MOXA_MUST_IIR_RDA ||
iir == MOXA_MUST_IIR_RTO ||
iir == MOXA_MUST_IIR_LSR)
- mxser_receive_chars(port,
+ mxser_receive_chars(tty, port,
&status);
} else {
status &= port->read_status_mask;
if (status & UART_LSR_DR)
- mxser_receive_chars(port,
+ mxser_receive_chars(tty, port,
&status);
}
msr = inb(port->ioaddr + UART_MSR);
if (msr & UART_MSR_ANY_DELTA)
- mxser_check_modem_status(port, msr);
+ mxser_check_modem_status(tty, port, msr);
if (port->board->chip_flag) {
if (iir == 0x02 && (status &
UART_LSR_THRE))
- mxser_transmit_chars(port);
+ mxser_transmit_chars(tty, port);
} else {
if (status & UART_LSR_THRE)
- mxser_transmit_chars(port);
+ mxser_transmit_chars(tty, port);
}
+ tty_kref_put(tty);
} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
spin_unlock(&port->slock);
}
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 69ec6399c71..bacb3e2872a 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
break;
default:
- error = n_tty_ioctl (tty, file, cmd, arg);
+ error = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
}
return error;
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index ae377aa473b..4a8215a89ad 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -372,14 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo,
static void put_char(struct r3964_info *pInfo, unsigned char ch)
{
struct tty_struct *tty = pInfo->tty;
-
- if (tty == NULL)
- return;
-
/* FIXME: put_char should not be called from an IRQ */
- if (tty->ops->put_char) {
- tty->ops->put_char(tty, ch);
- }
+ tty_put_char(tty, ch);
pInfo->bcc ^= ch;
}
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 708c2b1dbe5..efbfe961265 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -26,7 +26,7 @@
*
* 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
* waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- * Also fixed a bug in BLOCKING mode where write_chan returns
+ * Also fixed a bug in BLOCKING mode where n_tty_write returns
* EAGAIN
*/
@@ -99,6 +99,7 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
static void n_tty_set_room(struct tty_struct *tty)
{
+ /* tty->read_cnt is not read locked ? */
int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
/*
@@ -121,6 +122,16 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
}
}
+/**
+ * put_tty_queue - add character to tty
+ * @c: character
+ * @tty: tty device
+ *
+ * Add a character to the tty read_buf queue. This is done under the
+ * read_lock to serialize character addition and also to protect us
+ * against parallel reads or flushes
+ */
+
static void put_tty_queue(unsigned char c, struct tty_struct *tty)
{
unsigned long flags;
@@ -137,14 +148,11 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty)
* check_unthrottle - allow new receive data
* @tty; tty device
*
- * Check whether to call the driver.unthrottle function.
- * We test the TTY_THROTTLED bit first so that it always
- * indicates the current state. The decision about whether
- * it is worth allowing more input has been taken by the caller.
+ * Check whether to call the driver unthrottle functions
+ *
* Can sleep, may be called under the atomic_read_lock mutex but
* this is not guaranteed.
*/
-
static void check_unthrottle(struct tty_struct *tty)
{
if (tty->count)
@@ -158,6 +166,8 @@ static void check_unthrottle(struct tty_struct *tty)
* Reset the read buffer counters, clear the flags,
* and make sure the driver is unthrottled. Called
* from n_tty_open() and n_tty_flush_buffer().
+ *
+ * Locking: tty_read_lock for read fields.
*/
static void reset_buffer_flags(struct tty_struct *tty)
{
@@ -181,7 +191,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
* at hangup) or when the N_TTY line discipline internally has to
* clean the pending queue (for example some signals).
*
- * Locking: ctrl_lock
+ * Locking: ctrl_lock, read_lock.
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
@@ -207,6 +217,8 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
*
* Report the number of characters buffered to be delivered to user
* at this instant in time.
+ *
+ * Locking: read_lock
*/
static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
@@ -346,7 +358,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
* the simple cases normally found and helps to generate blocks of
* symbols for the console driver and thus improve performance.
*
- * Called from write_chan under the tty layer write lock. Relies
+ * Called from n_tty_write under the tty layer write lock. Relies
* on lock_kernel for the tty->column state.
*/
@@ -410,6 +422,8 @@ break_out:
*
* Echo user input back onto the screen. This must be called only when
* L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ * Relies on BKL for tty column locking
*/
static void echo_char(unsigned char c, struct tty_struct *tty)
@@ -422,6 +436,12 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
opost(c, tty);
}
+/**
+ * finsh_erasing - complete erase
+ * @tty: tty doing the erase
+ *
+ * Relies on BKL for tty column locking
+ */
static inline void finish_erasing(struct tty_struct *tty)
{
if (tty->erasing) {
@@ -439,6 +459,8 @@ static inline void finish_erasing(struct tty_struct *tty)
* Perform erase and necessary output when an erase character is
* present in the stream from the driver layer. Handles the complexities
* of UTF-8 multibyte symbols.
+ *
+ * Locking: read_lock for tty buffers, BKL for column/erasing state
*/
static void eraser(unsigned char c, struct tty_struct *tty)
@@ -447,6 +469,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
int head, seen_alnums, cnt;
unsigned long flags;
+ /* FIXME: locking needed ? */
if (tty->read_head == tty->canon_head) {
/* opost('\a', tty); */ /* what do you think? */
return;
@@ -481,6 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
}
seen_alnums = 0;
+ /* FIXME: Locking ?? */
while (tty->read_head != tty->canon_head) {
head = tty->read_head;
@@ -583,6 +607,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* may caus terminal flushing to take place according to the termios
* settings and character used. Called from the driver receive_buf
* path so serialized.
+ *
+ * Locking: ctrl_lock, read_lock (both via flush buffer)
*/
static inline void isig(int sig, struct tty_struct *tty, int flush)
@@ -1007,12 +1033,26 @@ int is_ignored(int sig)
* and is protected from re-entry by the tty layer. The user is
* guaranteed that this function will not be re-entered or in progress
* when the ldisc is closed.
+ *
+ * Locking: Caller holds tty->termios_mutex
*/
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- if (!tty)
- return;
+ int canon_change = 1;
+ BUG_ON(!tty);
+
+ if (old)
+ canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+ if (canon_change) {
+ memset(&tty->read_flags, 0, sizeof tty->read_flags);
+ tty->canon_head = tty->read_tail;
+ tty->canon_data = 0;
+ tty->erasing = 0;
+ }
+
+ if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+ wake_up_interruptible(&tty->read_wait);
tty->icanon = (L_ICANON(tty) != 0);
if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
@@ -1143,7 +1183,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
* @b: user data
* @nr: size of data
*
- * Helper function to speed up read_chan. It is only called when
+ * Helper function to speed up n_tty_read. It is only called when
* ICANON is off; it copies characters straight from the tty queue to
* user space directly. It can be profitably called twice; once to
* drain the space from the tail pointer to the (physical) end of the
@@ -1210,7 +1250,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
if (file->f_op->write != redirected_tty_write &&
current->signal->tty == tty) {
if (!tty->pgrp)
- printk(KERN_ERR "read_chan: no tty->pgrp!\n");
+ printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
else if (task_pgrp(current) != tty->pgrp) {
if (is_ignored(SIGTTIN) ||
is_current_pgrp_orphaned())
@@ -1225,7 +1265,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
/**
- * read_chan - read function for tty
+ * n_tty_read - read function for tty
* @tty: tty device
* @file: file object
* @buf: userspace buffer pointer
@@ -1239,7 +1279,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
* This code must be sure never to sleep through a hangup.
*/
-static ssize_t read_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t nr)
{
unsigned char __user *b = buf;
@@ -1254,10 +1294,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
do_it_again:
- if (!tty->read_buf) {
- printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n");
- return -EIO;
- }
+ BUG_ON(!tty->read_buf);
c = job_control(tty, file);
if (c < 0)
@@ -1444,7 +1481,7 @@ do_it_again:
}
/**
- * write_chan - write function for tty
+ * n_tty_write - write function for tty
* @tty: tty device
* @file: file object
* @buf: userspace buffer pointer
@@ -1458,7 +1495,7 @@ do_it_again:
* This code must be sure never to sleep through a hangup.
*/
-static ssize_t write_chan(struct tty_struct *tty, struct file *file,
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr)
{
const unsigned char *b = buf;
@@ -1532,7 +1569,7 @@ break_out:
}
/**
- * normal_poll - poll method for N_TTY
+ * n_tty_poll - poll method for N_TTY
* @tty: terminal device
* @file: file accessing it
* @wait: poll table
@@ -1545,7 +1582,7 @@ break_out:
* Called without the kernel lock held - fine
*/
-static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
+static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
poll_table *wait)
{
unsigned int mask = 0;
@@ -1573,6 +1610,44 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
return mask;
}
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+ int nr, head, tail;
+
+ if (!tty->canon_data)
+ return 0;
+ head = tty->canon_head;
+ tail = tty->read_tail;
+ nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+ /* Skip EOF-chars.. */
+ while (head != tail) {
+ if (test_bit(tail, tty->read_flags) &&
+ tty->read_buf[tail] == __DISABLED_CHAR)
+ nr--;
+ tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+ }
+ return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval;
+
+ switch (cmd) {
+ case TIOCOUTQ:
+ return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+ case TIOCINQ:
+ /* FIXME: Locking */
+ retval = tty->read_cnt;
+ if (L_ICANON(tty))
+ retval = inq_canon(tty);
+ return put_user(retval, (unsigned int __user *) arg);
+ default:
+ return n_tty_ioctl_helper(tty, file, cmd, arg);
+ }
+}
+
struct tty_ldisc_ops tty_ldisc_N_TTY = {
.magic = TTY_LDISC_MAGIC,
.name = "n_tty",
@@ -1580,11 +1655,11 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
.close = n_tty_close,
.flush_buffer = n_tty_flush_buffer,
.chars_in_buffer = n_tty_chars_in_buffer,
- .read = read_chan,
- .write = write_chan,
+ .read = n_tty_read,
+ .write = n_tty_write,
.ioctl = n_tty_ioctl,
.set_termios = n_tty_set_termios,
- .poll = normal_poll,
+ .poll = n_tty_poll,
.receive_buf = n_tty_receive_buf,
.write_wakeup = n_tty_write_wakeup
};
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index 66a0f931c66..9a34a193528 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -1599,7 +1599,10 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
return 0;
}
-/* Called when the userspace process close the tty, /dev/noz*. */
+/* Called when the userspace process close the tty, /dev/noz*. Also
+ called immediately if ntty_open fails in which case tty->driver_data
+ will be NULL an we exit by the first return */
+
static void ntty_close(struct tty_struct *tty, struct file *file)
{
struct nozomi *dc = get_dc_by_tty(tty);
diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c
index 3a23e7694d5..569f2f7743a 100644
--- a/drivers/char/pcmcia/ipwireless/tty.c
+++ b/drivers/char/pcmcia/ipwireless/tty.c
@@ -276,6 +276,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
struct ipw_tty *tty = linux_tty->driver_data;
int room;
+ /* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
@@ -397,6 +398,7 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set,
static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file)
{
struct ipw_tty *tty = linux_tty->driver_data;
+ /* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
@@ -412,6 +414,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct ipw_tty *tty = linux_tty->driver_data;
+ /* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
@@ -433,6 +436,8 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
if (!tty->open_count)
return -EINVAL;
+ /* FIXME: Exactly how is the tty object locked here .. */
+
switch (cmd) {
case TIOCGSERIAL:
return ipwireless_get_serial_info(tty, (void __user *) arg);
@@ -467,13 +472,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
}
return 0;
- case TCGETS:
- case TCGETA:
- return n_tty_ioctl(linux_tty, file, cmd, arg);
-
- case TCFLSH:
- return n_tty_ioctl(linux_tty, file, cmd, arg);
-
case FIONREAD:
{
int val = 0;
@@ -482,10 +480,11 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
return -EFAULT;
}
return 0;
+ case TCFLSH:
+ return tty_perform_flush(linux_tty, arg);
}
}
-
- return -ENOIOCTLCMD;
+ return tty_mode_ioctl(linux_tty, file, cmd , arg);
}
static int add_tty(dev_node_t *nodesp, int j,
@@ -588,6 +587,8 @@ void ipwireless_tty_free(struct ipw_tty *tty)
tty_hangup(ttyj->linux_tty);
/* Wait till the tty_hangup has completed */
flush_scheduled_work();
+ /* FIXME: Exactly how is the tty object locked here
+ against a parallel ioctl etc */
mutex_lock(&ttyj->ipw_tty_mutex);
}
while (ttyj->open_count)
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 76b27932d22..6d4582712b1 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -8,10 +8,12 @@
* Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
* waiting writers -- Sapan Bhatia <sapan@corewars.org>
*
- *
+ * When reading this code see also fs/devpts. In particular note that the
+ * driver_data field is used by the devpts side as a binding to the devpts
+ * inode.
*/
-#include <linux/module.h> /* For EXPORT_SYMBOL */
+#include <linux/module.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
@@ -23,26 +25,25 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/sysctl.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/devpts_fs.h>
+#include <asm/system.h>
+
/* These are global because they are accessed in tty_io.c */
#ifdef CONFIG_UNIX98_PTYS
struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver;
#endif
-static void pty_close(struct tty_struct * tty, struct file * filp)
+static void pty_close(struct tty_struct *tty, struct file *filp)
{
- if (!tty)
- return;
- if (tty->driver->subtype == PTY_TYPE_MASTER) {
- if (tty->count > 1)
- printk("master pty_close: count = %d!!\n", tty->count);
- } else {
+ BUG_ON(!tty);
+ if (tty->driver->subtype == PTY_TYPE_MASTER)
+ WARN_ON(tty->count > 1);
+ else {
if (tty->count > 2)
return;
}
@@ -59,7 +60,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
if (tty->driver == ptm_driver)
- devpts_pty_kill(tty->index);
+ devpts_pty_kill(tty->link);
#endif
tty_vhangup(tty->link);
}
@@ -69,13 +70,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
* The unthrottle routine is called by the line discipline to signal
* that it can receive more characters. For PTY's, the TTY_THROTTLED
* flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
* characters in the queue. This is necessary since each time this
* happens, we need to wake up any sleeping processes that could be
* (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
* for the pty buffer to be drained.
*/
-static void pty_unthrottle(struct tty_struct * tty)
+static void pty_unthrottle(struct tty_struct *tty)
{
struct tty_struct *o_tty = tty->link;
@@ -87,7 +88,7 @@ static void pty_unthrottle(struct tty_struct * tty)
}
/*
- * WSH 05/24/97: modified to
+ * WSH 05/24/97: modified to
* (1) use space in tty->flip instead of a shared temp buffer
* The flip buffers aren't being used for a pty, so there's lots
* of space available. The buffer is protected by a per-pty
@@ -100,7 +101,8 @@ static void pty_unthrottle(struct tty_struct * tty)
* not our partners. We can't just take the other one blindly without
* risking deadlocks.
*/
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct *tty, const unsigned char *buf,
+ int count)
{
struct tty_struct *to = tty->link;
int c;
@@ -112,7 +114,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
if (c > count)
c = count;
to->ldisc.ops->receive_buf(to, buf, NULL, c);
-
+
return c;
}
@@ -128,17 +130,17 @@ static int pty_write_room(struct tty_struct *tty)
/*
* WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior
- * The chars_in_buffer() value is used by the ldisc select() function
+ * The chars_in_buffer() value is used by the ldisc select() function
* to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
* The pty driver chars_in_buffer() Master/Slave must behave differently:
*
* The Master side needs to allow typed-ahead commands to accumulate
* while being canonicalized, so we report "our buffer" as empty until
* some threshold is reached, and then report the count. (Any count >
- * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock
- * the count returned must be 0 if no canonical data is available to be
+ * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock
+ * the count returned must be 0 if no canonical data is available to be
* read. (The N_TTY ldisc.chars_in_buffer now knows this.)
- *
+ *
* The Slave side passes all characters in raw mode to the Master side's
* buffer where they can be read immediately, so in this case we can
* return the true count in the buffer.
@@ -155,21 +157,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
/* The ldisc must report 0 if no characters available to be read */
count = to->ldisc.ops->chars_in_buffer(to);
- if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
+ if (tty->driver->subtype == PTY_TYPE_SLAVE)
+ return count;
- /* Master side driver ... if the other side's read buffer is less than
+ /* Master side driver ... if the other side's read buffer is less than
* half full, return 0 to allow writers to proceed; otherwise return
- * the count. This leaves a comfortable margin to avoid overflow,
+ * the count. This leaves a comfortable margin to avoid overflow,
* and still allows half a buffer's worth of typed-ahead commands.
*/
- return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
+ return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
}
/* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user * arg)
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
{
int val;
- if (get_user(val,arg))
+ if (get_user(val, arg))
return -EFAULT;
if (val)
set_bit(TTY_PTY_LOCK, &tty->flags);
@@ -182,13 +185,13 @@ static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
unsigned long flags;
-
+
if (!to)
return;
-
+
if (to->ldisc.ops->flush_buffer)
to->ldisc.ops->flush_buffer(to);
-
+
if (to->packet) {
spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -197,7 +200,7 @@ static void pty_flush_buffer(struct tty_struct *tty)
}
}
-static int pty_open(struct tty_struct *tty, struct file * filp)
+static int pty_open(struct tty_struct *tty, struct file *filp)
{
int retval = -ENODEV;
@@ -220,13 +223,65 @@ out:
return retval;
}
-static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void pty_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
+{
+ tty->termios->c_cflag &= ~(CSIZE | PARENB);
+ tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
{
- tty->termios->c_cflag &= ~(CSIZE | PARENB);
- tty->termios->c_cflag |= (CS8 | CREAD);
+ struct tty_struct *o_tty;
+ int idx = tty->index;
+ int retval;
+
+ o_tty = alloc_tty_struct();
+ if (!o_tty)
+ return -ENOMEM;
+ if (!try_module_get(driver->other->owner)) {
+ /* This cannot in fact currently happen */
+ free_tty_struct(o_tty);
+ return -ENOMEM;
+ }
+ initialize_tty_struct(o_tty, driver->other, idx);
+
+ /* We always use new tty termios data so we can do this
+ the easy way .. */
+ retval = tty_init_termios(tty);
+ if (retval)
+ goto free_mem_out;
+
+ retval = tty_init_termios(o_tty);
+ if (retval) {
+ tty_free_termios(tty);
+ goto free_mem_out;
+ }
+
+ /*
+ * Everything allocated ... set up the o_tty structure.
+ */
+ driver->other->ttys[idx] = o_tty;
+ tty_driver_kref_get(driver->other);
+ if (driver->subtype == PTY_TYPE_MASTER)
+ o_tty->count++;
+ /* Establish the links in both directions */
+ tty->link = o_tty;
+ o_tty->link = tty;
+
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+ return 0;
+free_mem_out:
+ module_put(o_tty->driver->owner);
+ free_tty_struct(o_tty);
+ return -ENOMEM;
}
+
static const struct tty_operations pty_ops = {
+ .install = pty_install,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@@ -329,8 +384,11 @@ static inline void legacy_pty_init(void) { }
* Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
*/
int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min = 0;
+static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count;
+
+static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = {
{
@@ -348,6 +406,7 @@ static struct ctl_table pty_table[] = {
.procname = "nr",
.maxlen = sizeof(int),
.mode = 0444,
+ .data = &pty_count,
.proc_handler = &proc_dointvec,
}, {
.ctl_name = 0
@@ -388,7 +447,127 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
+/**
+ * ptm_unix98_lookup - find a pty master
+ * @driver: ptm driver
+ * @idx: tty index
+ *
+ * Look up a pty master device. Called under the tty_mutex for now.
+ * This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+ struct inode *ptm_inode, int idx)
+{
+ struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
+ if (tty)
+ tty = tty->link;
+ return tty;
+}
+
+/**
+ * pts_unix98_lookup - find a pty slave
+ * @driver: pts driver
+ * @idx: tty index
+ *
+ * Look up a pty master device. Called under the tty_mutex for now.
+ * This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+ struct inode *pts_inode, int idx)
+{
+ struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+ /* Master must be open before slave */
+ if (!tty)
+ return ERR_PTR(-EIO);
+ return tty;
+}
+
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+ /* We have our own method as we don't use the tty index */
+ kfree(tty->termios);
+}
+
+/* We have no need to install and remove our tty objects as devpts does all
+ the work for us */
+
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct tty_struct *o_tty;
+ int idx = tty->index;
+
+ o_tty = alloc_tty_struct();
+ if (!o_tty)
+ return -ENOMEM;
+ if (!try_module_get(driver->other->owner)) {
+ /* This cannot in fact currently happen */
+ free_tty_struct(o_tty);
+ return -ENOMEM;
+ }
+ initialize_tty_struct(o_tty, driver->other, idx);
+
+ tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+ if (tty->termios == NULL)
+ goto free_mem_out;
+ *tty->termios = driver->init_termios;
+ tty->termios_locked = tty->termios + 1;
+
+ o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+ if (o_tty->termios == NULL)
+ goto free_mem_out;
+ *o_tty->termios = driver->other->init_termios;
+ o_tty->termios_locked = o_tty->termios + 1;
+
+ tty_driver_kref_get(driver->other);
+ if (driver->subtype == PTY_TYPE_MASTER)
+ o_tty->count++;
+ /* Establish the links in both directions */
+ tty->link = o_tty;
+ o_tty->link = tty;
+ /*
+ * All structures have been allocated, so now we install them.
+ * Failures after this point use release_tty to clean up, so
+ * there's no need to null out the local pointers.
+ */
+ tty_driver_kref_get(driver);
+ tty->count++;
+ pty_count++;
+ return 0;
+free_mem_out:
+ kfree(o_tty->termios);
+ module_put(o_tty->driver->owner);
+ free_tty_struct(o_tty);
+ kfree(tty->termios);
+ return -ENOMEM;
+}
+
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+ pty_count--;
+}
+
+static const struct tty_operations ptm_unix98_ops = {
+ .lookup = ptm_unix98_lookup,
+ .install = pty_unix98_install,
+ .remove = pty_unix98_remove,
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .ioctl = pty_unix98_ioctl,
+ .shutdown = pty_unix98_shutdown
+};
+
static const struct tty_operations pty_unix98_ops = {
+ .lookup = pts_unix98_lookup,
+ .install = pty_unix98_install,
+ .remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@@ -397,9 +576,73 @@ static const struct tty_operations pty_unix98_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
- .ioctl = pty_unix98_ioctl
+ .shutdown = pty_unix98_shutdown
};
+/**
+ * ptmx_open - open a unix 98 pty master
+ * @inode: inode of device file
+ * @filp: file pointer to tty
+ *
+ * Allocate a unix98 pty master device from the ptmx driver.
+ *
+ * Locking: tty_mutex protects the init_dev work. tty->count should
+ * protect the rest.
+ * allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int __ptmx_open(struct inode *inode, struct file *filp)
+{
+ struct tty_struct *tty;
+ int retval;
+ int index;
+
+ nonseekable_open(inode, filp);
+
+ /* find a device that is not in use. */
+ index = devpts_new_index(inode);
+ if (index < 0)
+ return index;
+
+ mutex_lock(&tty_mutex);
+ tty = tty_init_dev(ptm_driver, index, 1);
+ mutex_unlock(&tty_mutex);
+
+ if (IS_ERR(tty)) {
+ retval = PTR_ERR(tty);
+ goto out;
+ }
+
+ set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+ filp->private_data = tty;
+ file_move(filp, &tty->tty_files);
+
+ retval = devpts_pty_new(inode, tty->link);
+ if (retval)
+ goto out1;
+
+ retval = ptm_driver->ops->open(tty, filp);
+ if (!retval)
+ return 0;
+out1:
+ tty_release_dev(filp);
+ return retval;
+out:
+ devpts_kill_index(inode, index);
+ return retval;
+}
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+
+ lock_kernel();
+ ret = __ptmx_open(inode, filp);
+ unlock_kernel();
+ return ret;
+}
+
+static struct file_operations ptmx_fops;
static void __init unix98_pty_init(void)
{
@@ -427,7 +670,7 @@ static void __init unix98_pty_init(void)
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
- tty_set_operations(ptm_driver, &pty_unix98_ops);
+ tty_set_operations(ptm_driver, &ptm_unix98_ops);
pts_driver->owner = THIS_MODULE;
pts_driver->driver_name = "pty_slave";
@@ -443,16 +686,26 @@ static void __init unix98_pty_init(void)
pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
- tty_set_operations(pts_driver, &pty_ops);
-
+ tty_set_operations(pts_driver, &pty_unix98_ops);
+
if (tty_register_driver(ptm_driver))
panic("Couldn't register Unix98 ptm driver");
if (tty_register_driver(pts_driver))
panic("Couldn't register Unix98 pts driver");
- pty_table[1].data = &ptm_driver->refcount;
register_sysctl_table(pty_root_table);
+
+ /* Now create the /dev/ptmx special device */
+ tty_default_fops(&ptmx_fops);
+ ptmx_fops.open = ptmx_open;
+
+ cdev_init(&ptmx_cdev, &ptmx_fops);
+ if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
+ register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
+ panic("Couldn't register /dev/ptmx driver\n");
+ device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
}
+
#else
static inline void unix98_pty_init(void) { }
#endif
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index f53d4d00faf..b47710c1788 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -88,12 +88,12 @@
#endif
#ifdef CONFIG_SPARC32
-#include <linux/pci.h>
-#include <linux/jiffies.h>
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/io.h>
static unsigned long rtc_port;
-static int rtc_irq = PCI_IRQ_NONE;
+static int rtc_irq;
#endif
#ifdef CONFIG_HPET_RTC_IRQ
@@ -973,8 +973,8 @@ static int __init rtc_init(void)
char *guess = NULL;
#endif
#ifdef CONFIG_SPARC32
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
+ struct device_node *ebus_dp;
+ struct of_device *op;
#else
void *r;
#ifdef RTC_IRQ
@@ -983,12 +983,16 @@ static int __init rtc_init(void)
#endif
#ifdef CONFIG_SPARC32
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (strcmp(edev->prom_node->name, "rtc") == 0) {
- rtc_port = edev->resource[0].start;
- rtc_irq = edev->irqs[0];
- goto found;
+ for_each_node_by_name(ebus_dp, "ebus") {
+ struct device_node *dp;
+ for (dp = ebus_dp; dp; dp = dp->sibling) {
+ if (!strcmp(dp->name, "rtc")) {
+ op = of_find_device_by_node(dp);
+ if (op) {
+ rtc_port = op->resource[0].start;
+ rtc_irq = op->irqs[0];
+ goto found;
+ }
}
}
}
@@ -997,7 +1001,7 @@ static int __init rtc_init(void)
return -EIO;
found:
- if (rtc_irq == PCI_IRQ_NONE) {
+ if (!rtc_irq) {
rtc_has_irq = 0;
goto no_irq;
}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 19db1eb87c2..8b8f07a7f50 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -405,9 +405,9 @@ static unsigned int stl_baudrates[] = {
static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
static int stl_brdinit(struct stlbrd *brdp);
-static int stl_getportstats(struct stlport *portp, comstats_t __user *cp);
+static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp);
static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
-static int stl_waitcarrier(struct stlport *portp, struct file *filp);
+static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp);
/*
* CD1400 uart specific handling functions.
@@ -612,8 +612,9 @@ static struct class *stallion_class;
static void stl_cd_change(struct stlport *portp)
{
unsigned int oldsigs = portp->sigs;
+ struct tty_struct *tty = tty_port_tty_get(&portp->port);
- if (!portp->port.tty)
+ if (!tty)
return;
portp->sigs = stl_getsignals(portp);
@@ -623,7 +624,8 @@ static void stl_cd_change(struct stlport *portp)
if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
if (portp->port.flags & ASYNC_CHECK_CD)
- tty_hangup(portp->port.tty);
+ tty_hangup(tty);
+ tty_kref_put(tty);
}
/*
@@ -734,7 +736,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
* On the first open of the device setup the port hardware, and
* initialize the per port data structure.
*/
- portp->port.tty = tty;
+ tty_port_tty_set(&portp->port, tty);
tty->driver_data = portp;
portp->port.count++;
@@ -774,7 +776,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
* then also we might have to wait for carrier.
*/
if (!(filp->f_flags & O_NONBLOCK))
- if ((rc = stl_waitcarrier(portp, filp)) != 0)
+ if ((rc = stl_waitcarrier(tty, portp, filp)) != 0)
return rc;
portp->port.flags |= ASYNC_NORMAL_ACTIVE;
@@ -789,7 +791,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp)
* maybe because if we are clocal then we don't need to wait...
*/
-static int stl_waitcarrier(struct stlport *portp, struct file *filp)
+static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp,
+ struct file *filp)
{
unsigned long flags;
int rc, doclocal;
@@ -801,7 +804,7 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp)
spin_lock_irqsave(&stallion_lock, flags);
- if (portp->port.tty->termios->c_cflag & CLOCAL)
+ if (tty->termios->c_cflag & CLOCAL)
doclocal++;
portp->openwaitcnt++;
@@ -846,8 +849,6 @@ static void stl_flushbuffer(struct tty_struct *tty)
pr_debug("stl_flushbuffer(tty=%p)\n", tty);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -865,8 +866,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -949,7 +948,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
tty_ldisc_flush(tty);
tty->closing = 0;
- portp->port.tty = NULL;
+ tty_port_tty_set(&portp->port, NULL);
if (portp->openwaitcnt) {
if (portp->close_delay)
@@ -1033,8 +1032,6 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch)
pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
- if (tty == NULL)
- return -EINVAL;
portp = tty->driver_data;
if (portp == NULL)
return -EINVAL;
@@ -1070,8 +1067,6 @@ static void stl_flushchars(struct tty_struct *tty)
pr_debug("stl_flushchars(tty=%p)\n", tty);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1090,8 +1085,6 @@ static int stl_writeroom(struct tty_struct *tty)
pr_debug("stl_writeroom(tty=%p)\n", tty);
- if (tty == NULL)
- return 0;
portp = tty->driver_data;
if (portp == NULL)
return 0;
@@ -1122,8 +1115,6 @@ static int stl_charsinbuffer(struct tty_struct *tty)
pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
- if (tty == NULL)
- return 0;
portp = tty->driver_data;
if (portp == NULL)
return 0;
@@ -1183,8 +1174,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
* just quietly ignore any requests to change irq, etc.
*/
-static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
+static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp)
{
+ struct stlport * portp = tty->driver_data;
struct serial_struct sio;
pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
@@ -1205,7 +1197,7 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
portp->close_delay = sio.close_delay;
portp->closing_wait = sio.closing_wait;
portp->custom_divisor = sio.custom_divisor;
- stl_setport(portp, portp->port.tty->termios);
+ stl_setport(portp, tty->termios);
return 0;
}
@@ -1215,8 +1207,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file)
{
struct stlport *portp;
- if (tty == NULL)
- return -ENODEV;
portp = tty->driver_data;
if (portp == NULL)
return -ENODEV;
@@ -1232,8 +1222,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
struct stlport *portp;
int rts = -1, dtr = -1;
- if (tty == NULL)
- return -ENODEV;
portp = tty->driver_data;
if (portp == NULL)
return -ENODEV;
@@ -1262,8 +1250,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
arg);
- if (tty == NULL)
- return -ENODEV;
portp = tty->driver_data;
if (portp == NULL)
return -ENODEV;
@@ -1282,10 +1268,10 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
rc = stl_getserial(portp, argp);
break;
case TIOCSSERIAL:
- rc = stl_setserial(portp, argp);
+ rc = stl_setserial(tty, argp);
break;
case COM_GETPORTSTATS:
- rc = stl_getportstats(portp, argp);
+ rc = stl_getportstats(tty, portp, argp);
break;
case COM_CLRPORTSTATS:
rc = stl_clrportstats(portp, argp);
@@ -1317,8 +1303,6 @@ static void stl_start(struct tty_struct *tty)
pr_debug("stl_start(tty=%p)\n", tty);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1334,8 +1318,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1369,8 +1351,6 @@ static void stl_throttle(struct tty_struct *tty)
pr_debug("stl_throttle(tty=%p)\n", tty);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1389,8 +1369,6 @@ static void stl_unthrottle(struct tty_struct *tty)
pr_debug("stl_unthrottle(tty=%p)\n", tty);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1410,8 +1388,6 @@ static void stl_stop(struct tty_struct *tty)
pr_debug("stl_stop(tty=%p)\n", tty);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1432,8 +1408,6 @@ static void stl_hangup(struct tty_struct *tty)
pr_debug("stl_hangup(tty=%p)\n", tty);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1452,7 +1426,7 @@ static void stl_hangup(struct tty_struct *tty)
portp->tx.head = NULL;
portp->tx.tail = NULL;
}
- portp->port.tty = NULL;
+ tty_port_tty_set(&portp->port, NULL);
portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
portp->port.count = 0;
wake_up_interruptible(&portp->port.open_wait);
@@ -1466,8 +1440,6 @@ static int stl_breakctl(struct tty_struct *tty, int state)
pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
- if (tty == NULL)
- return -EINVAL;
portp = tty->driver_data;
if (portp == NULL)
return -EINVAL;
@@ -1484,8 +1456,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
- if (tty == NULL)
- return;
portp = tty->driver_data;
if (portp == NULL)
return;
@@ -1805,7 +1775,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
"(size=%Zd)\n", sizeof(struct stlport));
break;
}
-
+ tty_port_init(&portp->port);
portp->magic = STL_PORTMAGIC;
portp->portnr = i;
portp->brdnr = panelp->brdnr;
@@ -1832,6 +1802,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
struct stlpanel *panelp;
struct stlport *portp;
unsigned int j, k;
+ struct tty_struct *tty;
for (j = 0; j < STL_MAXPANELS; j++) {
panelp = brdp->panels[j];
@@ -1841,8 +1812,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp)
portp = panelp->ports[k];
if (portp == NULL)
continue;
- if (portp->port.tty != NULL)
- stl_hangup(portp->port.tty);
+ tty = tty_port_tty_get(&portp->port);
+ if (tty != NULL) {
+ stl_hangup(tty);
+ tty_kref_put(tty);
+ }
kfree(portp->tx.buf);
kfree(portp);
}
@@ -2498,7 +2472,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
* what port to get stats for (used through board control device).
*/
-static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
+static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp)
{
comstats_t stl_comstats;
unsigned char *head, *tail;
@@ -2525,18 +2499,17 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
portp->stats.rxbuffered = 0;
spin_lock_irqsave(&stallion_lock, flags);
- if (portp->port.tty != NULL)
- if (portp->port.tty->driver_data == portp) {
- portp->stats.ttystate = portp->port.tty->flags;
- /* No longer available as a statistic */
- portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */
- if (portp->port.tty->termios != NULL) {
- portp->stats.cflags = portp->port.tty->termios->c_cflag;
- portp->stats.iflags = portp->port.tty->termios->c_iflag;
- portp->stats.oflags = portp->port.tty->termios->c_oflag;
- portp->stats.lflags = portp->port.tty->termios->c_lflag;
- }
+ if (tty != NULL && portp->port.tty == tty) {
+ portp->stats.ttystate = tty->flags;
+ /* No longer available as a statistic */
+ portp->stats.rxbuffered = 1; /*tty->flip.count; */
+ if (tty->termios != NULL) {
+ portp->stats.cflags = tty->termios->c_cflag;
+ portp->stats.iflags = tty->termios->c_iflag;
+ portp->stats.oflags = tty->termios->c_oflag;
+ portp->stats.lflags = tty->termios->c_lflag;
}
+ }
spin_unlock_irqrestore(&stallion_lock, flags);
head = portp->tx.head;
@@ -2640,7 +2613,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
switch (cmd) {
case COM_GETPORTSTATS:
- rc = stl_getportstats(NULL, argp);
+ rc = stl_getportstats(NULL, NULL, argp);
break;
case COM_CLRPORTSTATS:
rc = stl_clrportstats(NULL, argp);
@@ -3243,7 +3216,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
if (portp == NULL)
return;
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
if (tty == NULL)
return;
@@ -3288,6 +3261,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state)
BRDDISABLE(portp->brdnr);
spin_unlock_irqrestore(&brd_lock, flags);
+ tty_kref_put(tty);
}
/*****************************************************************************/
@@ -3305,7 +3279,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
if (portp == NULL)
return;
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
if (tty == NULL)
return;
@@ -3325,6 +3299,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state)
}
BRDDISABLE(portp->brdnr);
spin_unlock_irqrestore(&brd_lock, flags);
+ tty_kref_put(tty);
}
/*****************************************************************************/
@@ -3478,6 +3453,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
int len, stlen;
char *head, *tail;
unsigned char ioack, srer;
+ struct tty_struct *tty;
pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
@@ -3504,8 +3480,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
if ((len == 0) || ((len < STL_TXBUFLOW) &&
(test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
set_bit(ASYI_TXLOW, &portp->istate);
- if (portp->port.tty)
- tty_wakeup(portp->port.tty);
+ tty = tty_port_tty_get(&portp->port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
}
if (len == 0) {
@@ -3569,7 +3548,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
return;
}
portp = panelp->ports[(ioack >> 3)];
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
outb((RDCR + portp->uartaddr), ioaddr);
@@ -3633,10 +3612,12 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
}
} else {
printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
+ tty_kref_put(tty);
return;
}
stl_rxalldone:
+ tty_kref_put(tty);
outb((EOSRR + portp->uartaddr), ioaddr);
outb(0, (ioaddr + EREG_DATA));
}
@@ -4175,7 +4156,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
if (portp == NULL)
return;
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
if (tty == NULL)
return;
@@ -4226,6 +4207,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state)
BRDDISABLE(portp->brdnr);
spin_unlock_irqrestore(&brd_lock, flags);
+ tty_kref_put(tty);
}
/*****************************************************************************/
@@ -4244,7 +4226,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
if (portp == NULL)
return;
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
if (tty == NULL)
return;
@@ -4269,6 +4251,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state)
}
BRDDISABLE(portp->brdnr);
spin_unlock_irqrestore(&brd_lock, flags);
+ tty_kref_put(tty);
}
/*****************************************************************************/
@@ -4408,6 +4391,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase)
static void stl_sc26198txisr(struct stlport *portp)
{
+ struct tty_struct *tty;
unsigned int ioaddr;
unsigned char mr0;
int len, stlen;
@@ -4422,8 +4406,11 @@ static void stl_sc26198txisr(struct stlport *portp)
if ((len == 0) || ((len < STL_TXBUFLOW) &&
(test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
set_bit(ASYI_TXLOW, &portp->istate);
- if (portp->port.tty)
- tty_wakeup(portp->port.tty);
+ tty = tty_port_tty_get(&portp->port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
}
if (len == 0) {
@@ -4476,7 +4463,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
ioaddr = portp->ioaddr;
outb(GIBCR, (ioaddr + XP_ADDR));
len = inb(ioaddr + XP_DATA) + 1;
@@ -4515,6 +4502,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
stl_sc26198txunflow(portp, tty);
}
}
+ tty_kref_put(tty);
}
/*****************************************************************************/
@@ -4528,7 +4516,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
struct tty_struct *tty;
unsigned int ioaddr;
- tty = portp->port.tty;
+ tty = tty_port_tty_get(&portp->port);
ioaddr = portp->ioaddr;
if (status & SR_RXPARITY)
@@ -4566,6 +4554,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char
if (status == 0)
portp->stats.rxtotal++;
}
+ tty_kref_put(tty);
}
/*****************************************************************************/
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index c385206f9db..5b8d7a1aa3e 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board,
del_timer(&board->timer);
if (pdev) {
#ifdef CONFIG_PCI
- pci_iounmap(pdev, board->base);
+ pci_iounmap(pdev, board->base2);
pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
#endif
} else {
@@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev,
return 0;
err_unmap:
- pci_iounmap(pdev, board->base);
+ pci_iounmap(pdev, board->base2);
err_reg:
pci_release_region(pdev, reg);
err_flag:
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index ae766d86845..1fee7034a38 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -954,72 +954,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel);
/*
* Device file system interface to the TPM
+ *
+ * It's assured that the chip will be opened just once,
+ * by the check of is_open variable, which is protected
+ * by driver_lock.
*/
int tpm_open(struct inode *inode, struct file *file)
{
- int rc = 0, minor = iminor(inode);
+ int minor = iminor(inode);
struct tpm_chip *chip = NULL, *pos;
- lock_kernel();
- spin_lock(&driver_lock);
-
- list_for_each_entry(pos, &tpm_chip_list, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
if (pos->vendor.miscdev.minor == minor) {
chip = pos;
+ get_device(chip->dev);
break;
}
}
+ rcu_read_unlock();
- if (chip == NULL) {
- rc = -ENODEV;
- goto err_out;
- }
+ if (!chip)
+ return -ENODEV;
- if (chip->num_opens) {
+ if (test_and_set_bit(0, &chip->is_open)) {
dev_dbg(chip->dev, "Another process owns this TPM\n");
- rc = -EBUSY;
- goto err_out;
+ put_device(chip->dev);
+ return -EBUSY;
}
- chip->num_opens++;
- get_device(chip->dev);
-
- spin_unlock(&driver_lock);
-
chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
if (chip->data_buffer == NULL) {
- chip->num_opens--;
+ clear_bit(0, &chip->is_open);
put_device(chip->dev);
- unlock_kernel();
return -ENOMEM;
}
atomic_set(&chip->data_pending, 0);
file->private_data = chip;
- unlock_kernel();
return 0;
-
-err_out:
- spin_unlock(&driver_lock);
- unlock_kernel();
- return rc;
}
EXPORT_SYMBOL_GPL(tpm_open);
+/*
+ * Called on file close
+ */
int tpm_release(struct inode *inode, struct file *file)
{
struct tpm_chip *chip = file->private_data;
+ del_singleshot_timer_sync(&chip->user_read_timer);
flush_scheduled_work();
- spin_lock(&driver_lock);
file->private_data = NULL;
- del_singleshot_timer_sync(&chip->user_read_timer);
atomic_set(&chip->data_pending, 0);
- chip->num_opens--;
- put_device(chip->dev);
kfree(chip->data_buffer);
- spin_unlock(&driver_lock);
+ clear_bit(0, &chip->is_open);
+ put_device(chip->dev);
return 0;
}
EXPORT_SYMBOL_GPL(tpm_release);
@@ -1093,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev)
}
spin_lock(&driver_lock);
-
- list_del(&chip->list);
-
+ list_del_rcu(&chip->list);
spin_unlock(&driver_lock);
+ synchronize_rcu();
misc_deregister(&chip->vendor.miscdev);
-
sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
tpm_bios_log_teardown(chip->bios_dir);
@@ -1144,25 +1133,33 @@ int tpm_pm_resume(struct device *dev)
}
EXPORT_SYMBOL_GPL(tpm_pm_resume);
+/* In case vendor provided release function, call it too.*/
+
+void tpm_dev_vendor_release(struct tpm_chip *chip)
+{
+ if (chip->vendor.release)
+ chip->vendor.release(chip->dev);
+
+ clear_bit(chip->dev_num, dev_mask);
+ kfree(chip->vendor.miscdev.name);
+}
+EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
+
+
/*
* Once all references to platform device are down to 0,
* release all allocated structures.
- * In case vendor provided release function,
- * call it too.
*/
static void tpm_dev_release(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
- if (chip->vendor.release)
- chip->vendor.release(dev);
+ tpm_dev_vendor_release(chip);
chip->release(dev);
-
- clear_bit(chip->dev_num, dev_mask);
- kfree(chip->vendor.miscdev.name);
kfree(chip);
}
+EXPORT_SYMBOL_GPL(tpm_dev_release);
/*
* Called from tpm_<specific>.c probe function only for devices
@@ -1171,8 +1168,8 @@ static void tpm_dev_release(struct device *dev)
* upon errant exit from this function specific probe function should call
* pci_disable_device
*/
-struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific
- *entry)
+struct tpm_chip *tpm_register_hardware(struct device *dev,
+ const struct tpm_vendor_specific *entry)
{
#define DEVNAME_SIZE 7
@@ -1231,21 +1228,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
return NULL;
}
- spin_lock(&driver_lock);
-
- list_add(&chip->list, &tpm_chip_list);
-
- spin_unlock(&driver_lock);
-
if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
- list_del(&chip->list);
misc_deregister(&chip->vendor.miscdev);
put_device(chip->dev);
+
return NULL;
}
chip->bios_dir = tpm_bios_log_setup(devname);
+ /* Make chip available */
+ spin_lock(&driver_lock);
+ list_add_rcu(&chip->list, &tpm_chip_list);
+ spin_unlock(&driver_lock);
+
return chip;
}
EXPORT_SYMBOL_GPL(tpm_register_hardware);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e885148b4cf..8e30df4a438 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -90,7 +90,7 @@ struct tpm_chip {
struct device *dev; /* Device stuff */
int dev_num; /* /dev/tpm# */
- int num_opens; /* only one allowed */
+ unsigned long is_open; /* only one allowed */
int time_expired;
/* Data passed to and from the tpm via the read/write calls */
@@ -132,6 +132,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
const struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *);
extern int tpm_release(struct inode *, struct file *);
+extern void tpm_dev_vendor_release(struct tpm_chip *);
extern ssize_t tpm_write(struct file *, const char __user *, size_t,
loff_t *);
extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index ed1879c0dd8..717af7ad1bd 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -630,12 +630,23 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
{"", 0} /* Terminator */
};
+static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
+{
+ struct tpm_chip *chip = pnp_get_drvdata(dev);
+
+ tpm_dev_vendor_release(chip);
+
+ kfree(chip);
+}
+
+
static struct pnp_driver tis_pnp_driver = {
.name = "tpm_tis",
.id_table = tpm_pnp_tbl,
.probe = tpm_tis_pnp_init,
.suspend = tpm_tis_pnp_suspend,
.resume = tpm_tis_pnp_resume,
+ .remove = tpm_tis_pnp_remove,
};
#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
@@ -683,6 +694,7 @@ static void __exit cleanup_tis(void)
spin_lock(&tis_lock);
list_for_each_entry_safe(i, j, &tis_chips, list) {
chip = to_tpm_chip(i);
+ tpm_remove_hardware(chip->dev);
iowrite32(~TPM_GLOBAL_INT_ENABLE &
ioread32(chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.
@@ -694,9 +706,9 @@ static void __exit cleanup_tis(void)
free_irq(chip->vendor.irq, chip);
iounmap(i->iobase);
list_del(&i->list);
- tpm_remove_hardware(chip->dev);
}
spin_unlock(&tis_lock);
+
if (force) {
platform_device_unregister(pdev);
driver_unregister(&tis_drv);
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index 3582f43345a..5787249934c 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
audit_log_format(ab, " data=");
- audit_log_n_untrustedstring(ab, buf->data, buf->valid);
+ audit_log_n_hex(ab, buf->data, buf->valid);
audit_log_end(ab);
}
buf->valid = 0;
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
new file mode 100644
index 00000000000..810ee25d66a
--- /dev/null
+++ b/drivers/char/tty_buffer.c
@@ -0,0 +1,511 @@
+/*
+ * Tty buffer allocation management
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/**
+ * tty_buffer_free_all - free buffers used by a tty
+ * @tty: tty to free from
+ *
+ * Remove all the buffers pending on a tty whether queued with data
+ * or in the free ring. Must be called when the tty is no longer in use
+ *
+ * Locking: none
+ */
+
+void tty_buffer_free_all(struct tty_struct *tty)
+{
+ struct tty_buffer *thead;
+ while ((thead = tty->buf.head) != NULL) {
+ tty->buf.head = thead->next;
+ kfree(thead);
+ }
+ while ((thead = tty->buf.free) != NULL) {
+ tty->buf.free = thead->next;
+ kfree(thead);
+ }
+ tty->buf.tail = NULL;
+ tty->buf.memory_used = 0;
+}
+
+/**
+ * tty_buffer_alloc - allocate a tty buffer
+ * @tty: tty device
+ * @size: desired size (characters)
+ *
+ * Allocate a new tty buffer to hold the desired number of characters.
+ * Return NULL if out of memory or the allocation would exceed the
+ * per device queue
+ *
+ * Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+{
+ struct tty_buffer *p;
+
+ if (tty->buf.memory_used + size > 65536)
+ return NULL;
+ p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+ if (p == NULL)
+ return NULL;
+ p->used = 0;
+ p->size = size;
+ p->next = NULL;
+ p->commit = 0;
+ p->read = 0;
+ p->char_buf_ptr = (char *)(p->data);
+ p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+ tty->buf.memory_used += size;
+ return p;
+}
+
+/**
+ * tty_buffer_free - free a tty buffer
+ * @tty: tty owning the buffer
+ * @b: the buffer to free
+ *
+ * Free a tty buffer, or add it to the free list according to our
+ * internal strategy
+ *
+ * Locking: Caller must hold tty->buf.lock
+ */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+ /* Dumb strategy for now - should keep some stats */
+ tty->buf.memory_used -= b->size;
+ WARN_ON(tty->buf.memory_used < 0);
+
+ if (b->size >= 512)
+ kfree(b);
+ else {
+ b->next = tty->buf.free;
+ tty->buf.free = b;
+ }
+}
+
+/**
+ * __tty_buffer_flush - flush full tty buffers
+ * @tty: tty to flush
+ *
+ * flush all the buffers containing receive data. Caller must
+ * hold the buffer lock and must have ensured no parallel flush to
+ * ldisc is running.
+ *
+ * Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+ struct tty_buffer *thead;
+
+ while ((thead = tty->buf.head) != NULL) {
+ tty->buf.head = thead->next;
+ tty_buffer_free(tty, thead);
+ }
+ tty->buf.tail = NULL;
+}
+
+/**
+ * tty_buffer_flush - flush full tty buffers
+ * @tty: tty to flush
+ *
+ * flush all the buffers containing receive data. If the buffer is
+ * being processed by flush_to_ldisc then we defer the processing
+ * to that function
+ *
+ * Locking: none
+ */
+
+void tty_buffer_flush(struct tty_struct *tty)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+
+ /* If the data is being pushed to the tty layer then we can't
+ process it here. Instead set a flag and the flush_to_ldisc
+ path will process the flush request before it exits */
+ if (test_bit(TTY_FLUSHING, &tty->flags)) {
+ set_bit(TTY_FLUSHPENDING, &tty->flags);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ wait_event(tty->read_wait,
+ test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+ return;
+ } else
+ __tty_buffer_flush(tty);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
+ * tty_buffer_find - find a free tty buffer
+ * @tty: tty owning the buffer
+ * @size: characters wanted
+ *
+ * Locate an existing suitable tty buffer or if we are lacking one then
+ * allocate a new one. We round our buffers off in 256 character chunks
+ * to get better allocation behaviour.
+ *
+ * Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+{
+ struct tty_buffer **tbh = &tty->buf.free;
+ while ((*tbh) != NULL) {
+ struct tty_buffer *t = *tbh;
+ if (t->size >= size) {
+ *tbh = t->next;
+ t->next = NULL;
+ t->used = 0;
+ t->commit = 0;
+ t->read = 0;
+ tty->buf.memory_used += t->size;
+ return t;
+ }
+ tbh = &((*tbh)->next);
+ }
+ /* Round the buffer size out */
+ size = (size + 0xFF) & ~0xFF;
+ return tty_buffer_alloc(tty, size);
+ /* Should possibly check if this fails for the largest buffer we
+ have queued and recycle that ? */
+}
+
+/**
+ * tty_buffer_request_room - grow tty buffer if needed
+ * @tty: tty structure
+ * @size: size desired
+ *
+ * Make at least size bytes of linear space available for the tty
+ * buffer. If we fail return the size we managed to find.
+ *
+ * Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+ struct tty_buffer *b, *n;
+ int left;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+
+ /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
+ remove this conditional if its worth it. This would be invisible
+ to the callers */
+ if ((b = tty->buf.tail) != NULL)
+ left = b->size - b->used;
+ else
+ left = 0;
+
+ if (left < size) {
+ /* This is the slow path - looking for new buffers to use */
+ if ((n = tty_buffer_find(tty, size)) != NULL) {
+ if (b != NULL) {
+ b->next = n;
+ b->commit = b->used;
+ } else
+ tty->buf.head = n;
+ tty->buf.tail = n;
+ } else
+ size = left;
+ }
+
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ return size;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+/**
+ * tty_insert_flip_string - Add characters to the tty buffer
+ * @tty: tty structure
+ * @chars: characters
+ * @size: size
+ *
+ * Queue a series of bytes to the tty buffering. All the characters
+ * passed are marked as without error. Returns the number added.
+ *
+ * Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
+ size_t size)
+{
+ int copied = 0;
+ do {
+ int space = tty_buffer_request_room(tty, size - copied);
+ struct tty_buffer *tb = tty->buf.tail;
+ /* If there is no space then tb may be NULL */
+ if (unlikely(space == 0))
+ break;
+ memcpy(tb->char_buf_ptr + tb->used, chars, space);
+ memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+ tb->used += space;
+ copied += space;
+ chars += space;
+ /* There is a small chance that we need to split the data over
+ several buffers. If this is the case we must loop */
+ } while (unlikely(size > copied));
+ return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string);
+
+/**
+ * tty_insert_flip_string_flags - Add characters to the tty buffer
+ * @tty: tty structure
+ * @chars: characters
+ * @flags: flag bytes
+ * @size: size
+ *
+ * Queue a series of bytes to the tty buffering. For each character
+ * the flags array indicates the status of the character. Returns the
+ * number added.
+ *
+ * Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+ const unsigned char *chars, const char *flags, size_t size)
+{
+ int copied = 0;
+ do {
+ int space = tty_buffer_request_room(tty, size - copied);
+ struct tty_buffer *tb = tty->buf.tail;
+ /* If there is no space then tb may be NULL */
+ if (unlikely(space == 0))
+ break;
+ memcpy(tb->char_buf_ptr + tb->used, chars, space);
+ memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+ tb->used += space;
+ copied += space;
+ chars += space;
+ flags += space;
+ /* There is a small chance that we need to split the data over
+ several buffers. If this is the case we must loop */
+ } while (unlikely(size > copied));
+ return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
+
+/**
+ * tty_schedule_flip - push characters to ldisc
+ * @tty: tty to push from
+ *
+ * Takes any pending buffers and transfers their ownership to the
+ * ldisc side of the queue. It then schedules those characters for
+ * processing by the line discipline.
+ *
+ * Locking: Takes tty->buf.lock
+ */
+
+void tty_schedule_flip(struct tty_struct *tty)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ if (tty->buf.tail != NULL)
+ tty->buf.tail->commit = tty->buf.tail->used;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+/**
+ * tty_prepare_flip_string - make room for characters
+ * @tty: tty
+ * @chars: return pointer for character write area
+ * @size: desired size
+ *
+ * Prepare a block of space in the buffer for data. Returns the length
+ * available and buffer pointer to the space which is now allocated and
+ * accounted for as ready for normal characters. This is used for drivers
+ * that need their own block copy routines into the buffer. There is no
+ * guarantee the buffer is a DMA target!
+ *
+ * Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
+ size_t size)
+{
+ int space = tty_buffer_request_room(tty, size);
+ if (likely(space)) {
+ struct tty_buffer *tb = tty->buf.tail;
+ *chars = tb->char_buf_ptr + tb->used;
+ memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+ tb->used += space;
+ }
+ return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+
+/**
+ * tty_prepare_flip_string_flags - make room for characters
+ * @tty: tty
+ * @chars: return pointer for character write area
+ * @flags: return pointer for status flag write area
+ * @size: desired size
+ *
+ * Prepare a block of space in the buffer for data. Returns the length
+ * available and buffer pointer to the space which is now allocated and
+ * accounted for as ready for characters. This is used for drivers
+ * that need their own block copy routines into the buffer. There is no
+ * guarantee the buffer is a DMA target!
+ *
+ * Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string_flags(struct tty_struct *tty,
+ unsigned char **chars, char **flags, size_t size)
+{
+ int space = tty_buffer_request_room(tty, size);
+ if (likely(space)) {
+ struct tty_buffer *tb = tty->buf.tail;
+ *chars = tb->char_buf_ptr + tb->used;
+ *flags = tb->flag_buf_ptr + tb->used;
+ tb->used += space;
+ }
+ return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+
+
+
+/**
+ * flush_to_ldisc
+ * @work: tty structure passed from work queue.
+ *
+ * This routine is called out of the software interrupt to flush data
+ * from the buffer chain to the line discipline.
+ *
+ * Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ * while invoking the line discipline receive_buf method. The
+ * receive_buf method is single threaded for each tty instance.
+ */
+
+static void flush_to_ldisc(struct work_struct *work)
+{
+ struct tty_struct *tty =
+ container_of(work, struct tty_struct, buf.work.work);
+ unsigned long flags;
+ struct tty_ldisc *disc;
+ struct tty_buffer *tbuf, *head;
+ char *char_buf;
+ unsigned char *flag_buf;
+
+ disc = tty_ldisc_ref(tty);
+ if (disc == NULL) /* !TTY_LDISC */
+ return;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ /* So we know a flush is running */
+ set_bit(TTY_FLUSHING, &tty->flags);
+ head = tty->buf.head;
+ if (head != NULL) {
+ tty->buf.head = NULL;
+ for (;;) {
+ int count = head->commit - head->read;
+ if (!count) {
+ if (head->next == NULL)
+ break;
+ tbuf = head;
+ head = head->next;
+ tty_buffer_free(tty, tbuf);
+ continue;
+ }
+ /* Ldisc or user is trying to flush the buffers
+ we are feeding to the ldisc, stop feeding the
+ line discipline as we want to empty the queue */
+ if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+ break;
+ if (!tty->receive_room) {
+ schedule_delayed_work(&tty->buf.work, 1);
+ break;
+ }
+ if (count > tty->receive_room)
+ count = tty->receive_room;
+ char_buf = head->char_buf_ptr + head->read;
+ flag_buf = head->flag_buf_ptr + head->read;
+ head->read += count;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ disc->ops->receive_buf(tty, char_buf,
+ flag_buf, count);
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ }
+ /* Restore the queue head */
+ tty->buf.head = head;
+ }
+ /* We may have a deferred request to flush the input buffer,
+ if so pull the chain under the lock and empty the queue */
+ if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+ __tty_buffer_flush(tty);
+ clear_bit(TTY_FLUSHPENDING, &tty->flags);
+ wake_up(&tty->read_wait);
+ }
+ clear_bit(TTY_FLUSHING, &tty->flags);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+ tty_ldisc_deref(disc);
+}
+
+/**
+ * tty_flip_buffer_push - terminal
+ * @tty: tty to push
+ *
+ * Queue a push of the terminal flip buffers to the line discipline. This
+ * function must not be called from IRQ context if tty->low_latency is set.
+ *
+ * In the event of the queue being busy for flipping the work will be
+ * held off and retried later.
+ *
+ * Locking: tty buffer lock. Driver locks in low latency mode.
+ */
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ if (tty->buf.tail != NULL)
+ tty->buf.tail->commit = tty->buf.tail->used;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+ if (tty->low_latency)
+ flush_to_ldisc(&tty->buf.work.work);
+ else
+ schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/**
+ * tty_buffer_init - prepare a tty buffer structure
+ * @tty: tty to initialise
+ *
+ * Set up the initial state of the buffer management for a tty device.
+ * Must be called before the other tty buffer functions are used.
+ *
+ * Locking: none
+ */
+
+void tty_buffer_init(struct tty_struct *tty)
+{
+ spin_lock_init(&tty->buf.lock);
+ tty->buf.head = NULL;
+ tty->buf.tail = NULL;
+ tty->buf.free = NULL;
+ tty->buf.memory_used = 0;
+ INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+}
+
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index e4dce870954..7053d633369 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -49,7 +49,7 @@
* implement CONFIG_VT and generalize console device interface.
* -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
*
- * Rewrote init_dev and release_dev to eliminate races.
+ * Rewrote tty_init_dev and tty_release_dev to eliminate races.
* -- Bill Hawes <whawes@star.net>, June 97
*
* Added devfs support.
@@ -136,13 +136,6 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
DEFINE_MUTEX(tty_mutex);
EXPORT_SYMBOL(tty_mutex);
-#ifdef CONFIG_UNIX98_PTYS
-extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
-static int ptmx_open(struct inode *, struct file *);
-#endif
-
-static void initialize_tty_struct(struct tty_struct *tty);
-
static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -171,13 +164,11 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
* Locking: none
*/
-static struct tty_struct *alloc_tty_struct(void)
+struct tty_struct *alloc_tty_struct(void)
{
return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
}
-static void tty_buffer_free_all(struct tty_struct *);
-
/**
* free_tty_struct - free a disused tty
* @tty: tty struct to free
@@ -187,7 +178,7 @@ static void tty_buffer_free_all(struct tty_struct *);
* Locking: none. Must be called after tty is definitely unused
*/
-static inline void free_tty_struct(struct tty_struct *tty)
+void free_tty_struct(struct tty_struct *tty)
{
kfree(tty->write_buf);
tty_buffer_free_all(tty);
@@ -263,398 +254,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
return 0;
}
-/*
- * Tty buffer allocation management
- */
-
-/**
- * tty_buffer_free_all - free buffers used by a tty
- * @tty: tty to free from
- *
- * Remove all the buffers pending on a tty whether queued with data
- * or in the free ring. Must be called when the tty is no longer in use
- *
- * Locking: none
- */
-
-static void tty_buffer_free_all(struct tty_struct *tty)
-{
- struct tty_buffer *thead;
- while ((thead = tty->buf.head) != NULL) {
- tty->buf.head = thead->next;
- kfree(thead);
- }
- while ((thead = tty->buf.free) != NULL) {
- tty->buf.free = thead->next;
- kfree(thead);
- }
- tty->buf.tail = NULL;
- tty->buf.memory_used = 0;
-}
-
-/**
- * tty_buffer_init - prepare a tty buffer structure
- * @tty: tty to initialise
- *
- * Set up the initial state of the buffer management for a tty device.
- * Must be called before the other tty buffer functions are used.
- *
- * Locking: none
- */
-
-static void tty_buffer_init(struct tty_struct *tty)
-{
- spin_lock_init(&tty->buf.lock);
- tty->buf.head = NULL;
- tty->buf.tail = NULL;
- tty->buf.free = NULL;
- tty->buf.memory_used = 0;
-}
-
-/**
- * tty_buffer_alloc - allocate a tty buffer
- * @tty: tty device
- * @size: desired size (characters)
- *
- * Allocate a new tty buffer to hold the desired number of characters.
- * Return NULL if out of memory or the allocation would exceed the
- * per device queue
- *
- * Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
- struct tty_buffer *p;
-
- if (tty->buf.memory_used + size > 65536)
- return NULL;
- p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
- if (p == NULL)
- return NULL;
- p->used = 0;
- p->size = size;
- p->next = NULL;
- p->commit = 0;
- p->read = 0;
- p->char_buf_ptr = (char *)(p->data);
- p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
- tty->buf.memory_used += size;
- return p;
-}
-
-/**
- * tty_buffer_free - free a tty buffer
- * @tty: tty owning the buffer
- * @b: the buffer to free
- *
- * Free a tty buffer, or add it to the free list according to our
- * internal strategy
- *
- * Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
- /* Dumb strategy for now - should keep some stats */
- tty->buf.memory_used -= b->size;
- WARN_ON(tty->buf.memory_used < 0);
-
- if (b->size >= 512)
- kfree(b);
- else {
- b->next = tty->buf.free;
- tty->buf.free = b;
- }
-}
-
-/**
- * __tty_buffer_flush - flush full tty buffers
- * @tty: tty to flush
- *
- * flush all the buffers containing receive data. Caller must
- * hold the buffer lock and must have ensured no parallel flush to
- * ldisc is running.
- *
- * Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
- struct tty_buffer *thead;
-
- while ((thead = tty->buf.head) != NULL) {
- tty->buf.head = thead->next;
- tty_buffer_free(tty, thead);
- }
- tty->buf.tail = NULL;
-}
-
-/**
- * tty_buffer_flush - flush full tty buffers
- * @tty: tty to flush
- *
- * flush all the buffers containing receive data. If the buffer is
- * being processed by flush_to_ldisc then we defer the processing
- * to that function
- *
- * Locking: none
- */
-
-static void tty_buffer_flush(struct tty_struct *tty)
-{
- unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
-
- /* If the data is being pushed to the tty layer then we can't
- process it here. Instead set a flag and the flush_to_ldisc
- path will process the flush request before it exits */
- if (test_bit(TTY_FLUSHING, &tty->flags)) {
- set_bit(TTY_FLUSHPENDING, &tty->flags);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
- wait_event(tty->read_wait,
- test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
- return;
- } else
- __tty_buffer_flush(tty);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- * tty_buffer_find - find a free tty buffer
- * @tty: tty owning the buffer
- * @size: characters wanted
- *
- * Locate an existing suitable tty buffer or if we are lacking one then
- * allocate a new one. We round our buffers off in 256 character chunks
- * to get better allocation behaviour.
- *
- * Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
- struct tty_buffer **tbh = &tty->buf.free;
- while ((*tbh) != NULL) {
- struct tty_buffer *t = *tbh;
- if (t->size >= size) {
- *tbh = t->next;
- t->next = NULL;
- t->used = 0;
- t->commit = 0;
- t->read = 0;
- tty->buf.memory_used += t->size;
- return t;
- }
- tbh = &((*tbh)->next);
- }
- /* Round the buffer size out */
- size = (size + 0xFF) & ~0xFF;
- return tty_buffer_alloc(tty, size);
- /* Should possibly check if this fails for the largest buffer we
- have queued and recycle that ? */
-}
-
-/**
- * tty_buffer_request_room - grow tty buffer if needed
- * @tty: tty structure
- * @size: size desired
- *
- * Make at least size bytes of linear space available for the tty
- * buffer. If we fail return the size we managed to find.
- *
- * Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
- struct tty_buffer *b, *n;
- int left;
- unsigned long flags;
-
- spin_lock_irqsave(&tty->buf.lock, flags);
-
- /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
- remove this conditional if its worth it. This would be invisible
- to the callers */
- if ((b = tty->buf.tail) != NULL)
- left = b->size - b->used;
- else
- left = 0;
-
- if (left < size) {
- /* This is the slow path - looking for new buffers to use */
- if ((n = tty_buffer_find(tty, size)) != NULL) {
- if (b != NULL) {
- b->next = n;
- b->commit = b->used;
- } else
- tty->buf.head = n;
- tty->buf.tail = n;
- } else
- size = left;
- }
-
- spin_unlock_irqrestore(&tty->buf.lock, flags);
- return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- * tty_insert_flip_string - Add characters to the tty buffer
- * @tty: tty structure
- * @chars: characters
- * @size: size
- *
- * Queue a series of bytes to the tty buffering. All the characters
- * passed are marked as without error. Returns the number added.
- *
- * Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
- size_t size)
-{
- int copied = 0;
- do {
- int space = tty_buffer_request_room(tty, size - copied);
- struct tty_buffer *tb = tty->buf.tail;
- /* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
- break;
- memcpy(tb->char_buf_ptr + tb->used, chars, space);
- memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
- tb->used += space;
- copied += space;
- chars += space;
- /* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
- } while (unlikely(size > copied));
- return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string);
-
-/**
- * tty_insert_flip_string_flags - Add characters to the tty buffer
- * @tty: tty structure
- * @chars: characters
- * @flags: flag bytes
- * @size: size
- *
- * Queue a series of bytes to the tty buffering. For each character
- * the flags array indicates the status of the character. Returns the
- * number added.
- *
- * Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
- const unsigned char *chars, const char *flags, size_t size)
-{
- int copied = 0;
- do {
- int space = tty_buffer_request_room(tty, size - copied);
- struct tty_buffer *tb = tty->buf.tail;
- /* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
- break;
- memcpy(tb->char_buf_ptr + tb->used, chars, space);
- memcpy(tb->flag_buf_ptr + tb->used, flags, space);
- tb->used += space;
- copied += space;
- chars += space;
- flags += space;
- /* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
- } while (unlikely(size > copied));
- return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- * tty_schedule_flip - push characters to ldisc
- * @tty: tty to push from
- *
- * Takes any pending buffers and transfers their ownership to the
- * ldisc side of the queue. It then schedules those characters for
- * processing by the line discipline.
- *
- * Locking: Takes tty->buf.lock
- */
-
-void tty_schedule_flip(struct tty_struct *tty)
-{
- unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL)
- tty->buf.tail->commit = tty->buf.tail->used;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
- schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- * tty_prepare_flip_string - make room for characters
- * @tty: tty
- * @chars: return pointer for character write area
- * @size: desired size
- *
- * Prepare a block of space in the buffer for data. Returns the length
- * available and buffer pointer to the space which is now allocated and
- * accounted for as ready for normal characters. This is used for drivers
- * that need their own block copy routines into the buffer. There is no
- * guarantee the buffer is a DMA target!
- *
- * Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
- size_t size)
-{
- int space = tty_buffer_request_room(tty, size);
- if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
- tb->used += space;
- }
- return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- * tty_prepare_flip_string_flags - make room for characters
- * @tty: tty
- * @chars: return pointer for character write area
- * @flags: return pointer for status flag write area
- * @size: desired size
- *
- * Prepare a block of space in the buffer for data. Returns the length
- * available and buffer pointer to the space which is now allocated and
- * accounted for as ready for characters. This is used for drivers
- * that need their own block copy routines into the buffer. There is no
- * guarantee the buffer is a DMA target!
- *
- * Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
- unsigned char **chars, char **flags, size_t size)
-{
- int space = tty_buffer_request_room(tty, size);
- if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- *flags = tb->flag_buf_ptr + tb->used;
- tb->used += space;
- }
- return space;
-}
-
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
/**
* get_tty_driver - find device of a tty
* @dev_t: device identifier
@@ -675,7 +274,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
if (device < base || device >= base + p->num)
continue;
*index = device - base;
- return p;
+ return tty_driver_kref_get(p);
}
return NULL;
}
@@ -719,7 +318,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (tty_line >= 0 && tty_line <= p->num && p->ops &&
p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
- res = p;
+ res = tty_driver_kref_get(p);
*line = tty_line;
break;
}
@@ -819,20 +418,6 @@ static const struct file_operations tty_fops = {
.fasync = tty_fasync,
};
-#ifdef CONFIG_UNIX98_PTYS
-static const struct file_operations ptmx_fops = {
- .llseek = no_llseek,
- .read = tty_read,
- .write = tty_write,
- .poll = tty_poll,
- .unlocked_ioctl = tty_ioctl,
- .compat_ioctl = tty_compat_ioctl,
- .open = ptmx_open,
- .release = tty_release,
- .fasync = tty_fasync,
-};
-#endif
-
static const struct file_operations console_fops = {
.llseek = no_llseek,
.read = tty_read,
@@ -953,6 +538,7 @@ static void do_tty_hangup(struct work_struct *work)
struct tty_ldisc *ld;
int closecount = 0, n;
unsigned long flags;
+ int refs = 0;
if (!tty)
return;
@@ -1019,8 +605,12 @@ static void do_tty_hangup(struct work_struct *work)
if (tty->session) {
do_each_pid_task(tty->session, PIDTYPE_SID, p) {
spin_lock_irq(&p->sighand->siglock);
- if (p->signal->tty == tty)
+ if (p->signal->tty == tty) {
p->signal->tty = NULL;
+ /* We defer the dereferences outside fo
+ the tasklist lock */
+ refs++;
+ }
if (!p->signal->leader) {
spin_unlock_irq(&p->sighand->siglock);
continue;
@@ -1046,6 +636,10 @@ static void do_tty_hangup(struct work_struct *work)
tty->ctrl_status = 0;
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ /* Account for the p->signal references we killed */
+ while (refs--)
+ tty_kref_put(tty);
+
/*
* If one of the devices matches a console pointer, we
* cannot just call hangup() because that will cause
@@ -1115,6 +709,23 @@ void tty_vhangup(struct tty_struct *tty)
EXPORT_SYMBOL(tty_vhangup);
/**
+ * tty_vhangup_self - process vhangup for own ctty
+ *
+ * Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+ struct tty_struct *tty;
+
+ tty = get_current_tty();
+ if (tty) {
+ tty_vhangup(tty);
+ tty_kref_put(tty);
+ }
+}
+
+/**
* tty_hung_up_p - was tty hung up
* @filp: file pointer of tty
*
@@ -1167,16 +778,14 @@ void disassociate_ctty(int on_exit)
struct pid *tty_pgrp = NULL;
- mutex_lock(&tty_mutex);
tty = get_current_tty();
if (tty) {
tty_pgrp = get_pid(tty->pgrp);
lock_kernel();
- mutex_unlock(&tty_mutex);
- /* XXX: here we race, there is nothing protecting tty */
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
unlock_kernel();
+ tty_kref_put(tty);
} else if (on_exit) {
struct pid *old_pgrp;
spin_lock_irq(&current->sighand->siglock);
@@ -1188,7 +797,6 @@ void disassociate_ctty(int on_exit)
kill_pgrp(old_pgrp, SIGCONT, on_exit);
put_pid(old_pgrp);
}
- mutex_unlock(&tty_mutex);
return;
}
if (tty_pgrp) {
@@ -1203,8 +811,6 @@ void disassociate_ctty(int on_exit)
current->signal->tty_old_pgrp = NULL;
spin_unlock_irq(&current->sighand->siglock);
- mutex_lock(&tty_mutex);
- /* It is possible that do_tty_hangup has free'd this tty */
tty = get_current_tty();
if (tty) {
unsigned long flags;
@@ -1214,13 +820,13 @@ void disassociate_ctty(int on_exit)
tty->session = NULL;
tty->pgrp = NULL;
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ tty_kref_put(tty);
} else {
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
" = NULL", tty);
#endif
}
- mutex_unlock(&tty_mutex);
/* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
@@ -1420,19 +1026,19 @@ static inline ssize_t do_tty_write(
/* write_buf/write_cnt is protected by the atomic_write_lock mutex */
if (tty->write_cnt < chunk) {
- unsigned char *buf;
+ unsigned char *buf_chunk;
if (chunk < 1024)
chunk = 1024;
- buf = kmalloc(chunk, GFP_KERNEL);
- if (!buf) {
+ buf_chunk = kmalloc(chunk, GFP_KERNEL);
+ if (!buf_chunk) {
ret = -ENOMEM;
goto out;
}
kfree(tty->write_buf);
tty->write_cnt = chunk;
- tty->write_buf = buf;
+ tty->write_buf = buf_chunk;
}
/* Do the write .. */
@@ -1466,6 +1072,31 @@ out:
return ret;
}
+/**
+ * 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
+ * really needed.
+ *
+ * We must still hold the BKL and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+ lock_kernel();
+ if (tty) {
+ mutex_lock(&tty->atomic_write_lock);
+ if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
+ tty->ops->write(tty, msg, strlen(msg));
+ tty_write_unlock(tty);
+ }
+ unlock_kernel();
+ return;
+}
+
/**
* tty_write - write method for tty device file
@@ -1533,42 +1164,6 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
return tty_write(file, buf, count, ppos);
}
-void tty_port_init(struct tty_port *port)
-{
- memset(port, 0, sizeof(*port));
- init_waitqueue_head(&port->open_wait);
- init_waitqueue_head(&port->close_wait);
- mutex_init(&port->mutex);
- port->close_delay = (50 * HZ) / 100;
- port->closing_wait = (3000 * HZ) / 100;
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
- /* We may sleep in get_zeroed_page() */
- mutex_lock(&port->mutex);
- if (port->xmit_buf == NULL)
- port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
- mutex_unlock(&port->mutex);
- if (port->xmit_buf == NULL)
- return -ENOMEM;
- return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
- mutex_lock(&port->mutex);
- if (port->xmit_buf != NULL) {
- free_page((unsigned long)port->xmit_buf);
- port->xmit_buf = NULL;
- }
- mutex_unlock(&port->mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-
static char ptychar[] = "pqrstuvwxyzabcde";
/**
@@ -1592,7 +1187,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
}
/**
- * pty_line_name - generate name for a tty
+ * tty_line_name - generate name for a tty
* @driver: the tty driver in use
* @index: the minor number
* @p: output buffer of at least 7 bytes
@@ -1608,10 +1203,148 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
}
/**
- * init_dev - initialise a tty device
+ * tty_driver_lookup_tty() - find an existing tty, if any
+ * @driver: the driver for the tty
+ * @idx: the minor number
+ *
+ * Return the tty, if found or ERR_PTR() otherwise.
+ *
+ * Locking: tty_mutex must be held. If tty is found, the mutex must
+ * be held until the 'fast-open' is also done. Will change once we
+ * have refcounting in the driver and per driver locking
+ */
+struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+ struct inode *inode, int idx)
+{
+ struct tty_struct *tty;
+
+ if (driver->ops->lookup)
+ return driver->ops->lookup(driver, inode, idx);
+
+ tty = driver->ttys[idx];
+ return tty;
+}
+
+/**
+ * tty_init_termios - helper for termios setup
+ * @tty: the tty to set up
+ *
+ * Initialise the termios structures for this tty. Thus runs under
+ * the tty_mutex currently so we can be relaxed about ordering.
+ */
+
+int tty_init_termios(struct tty_struct *tty)
+{
+ struct ktermios *tp;
+ int idx = tty->index;
+
+ tp = tty->driver->termios[idx];
+ if (tp == NULL) {
+ tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+ if (tp == NULL)
+ return -ENOMEM;
+ memcpy(tp, &tty->driver->init_termios,
+ sizeof(struct ktermios));
+ tty->driver->termios[idx] = tp;
+ }
+ tty->termios = tp;
+ tty->termios_locked = tp + 1;
+
+ /* Compatibility until drivers always set this */
+ tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+ tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ return 0;
+}
+
+/**
+ * tty_driver_install_tty() - install a tty entry in the driver
+ * @driver: the driver for the tty
+ * @tty: the tty
+ *
+ * Install a tty object into the driver tables. The tty->index field
+ * will be set by the time this is called. This method is responsible
+ * for ensuring any need additional structures are allocated and
+ * configured.
+ *
+ * Locking: tty_mutex for now
+ */
+static int tty_driver_install_tty(struct tty_driver *driver,
+ struct tty_struct *tty)
+{
+ int idx = tty->index;
+
+ if (driver->ops->install)
+ return driver->ops->install(driver, tty);
+
+ if (tty_init_termios(tty) == 0) {
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+/**
+ * tty_driver_remove_tty() - remove a tty from the driver tables
+ * @driver: the driver for the tty
+ * @idx: the minor number
+ *
+ * Remvoe a tty object from the driver tables. The tty->index field
+ * will be set by the time this is called.
+ *
+ * Locking: tty_mutex for now
+ */
+static void tty_driver_remove_tty(struct tty_driver *driver,
+ struct tty_struct *tty)
+{
+ if (driver->ops->remove)
+ driver->ops->remove(driver, tty);
+ else
+ driver->ttys[tty->index] = NULL;
+}
+
+/*
+ * tty_reopen() - fast re-open of an open tty
+ * @tty - the tty to open
+ *
+ * Return 0 on success, -errno on error.
+ *
+ * Locking: tty_mutex must be held from the time the tty was found
+ * till this open completes.
+ */
+static int tty_reopen(struct tty_struct *tty)
+{
+ struct tty_driver *driver = tty->driver;
+
+ if (test_bit(TTY_CLOSING, &tty->flags))
+ return -EIO;
+
+ if (driver->type == TTY_DRIVER_TYPE_PTY &&
+ driver->subtype == PTY_TYPE_MASTER) {
+ /*
+ * special case for PTY masters: only one open permitted,
+ * and the slave side open count is incremented as well.
+ */
+ if (tty->count)
+ return -EIO;
+
+ tty->link->count++;
+ }
+ tty->count++;
+ tty->driver = driver; /* N.B. why do this every time?? */
+
+ WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+
+ return 0;
+}
+
+/**
+ * tty_init_dev - initialise a tty device
* @driver: tty driver we are opening a device on
* @idx: device index
- * @tty: returned tty structure
+ * @ret_tty: returned tty structure
+ * @first_ok: ok to open a new device (used by ptmx)
*
* Prepare a tty device. This may not be a "new" clean device but
* could also be an active device. The pty drivers require special
@@ -1631,37 +1364,16 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
* relaxed for the (most common) case of reopening a tty.
*/
-static int init_dev(struct tty_driver *driver, int idx,
- struct tty_struct **ret_tty)
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+ int first_ok)
{
- struct tty_struct *tty, *o_tty;
- struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
- struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
- int retval = 0;
+ struct tty_struct *tty;
+ int retval;
- /* check whether we're reopening an existing tty */
- if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
- tty = devpts_get_tty(idx);
- /*
- * If we don't have a tty here on a slave open, it's because
- * the master already started the close process and there's
- * no relation between devpts file and tty anymore.
- */
- if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
- retval = -EIO;
- goto end_init;
- }
- /*
- * It's safe from now on because init_dev() is called with
- * tty_mutex held and release_dev() won't change tty->count
- * or tty->flags without having to grab tty_mutex
- */
- if (tty && driver->subtype == PTY_TYPE_MASTER)
- tty = tty->link;
- } else {
- tty = driver->ttys[idx];
- }
- if (tty) goto fast_track;
+ /* Check if pty master is being opened multiple times */
+ if (driver->subtype == PTY_TYPE_MASTER &&
+ (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
+ return ERR_PTR(-EIO);
/*
* First time open is complex, especially for PTY devices.
@@ -1671,189 +1383,69 @@ static int init_dev(struct tty_driver *driver, int idx,
* and locked termios may be retained.)
*/
- if (!try_module_get(driver->owner)) {
- retval = -ENODEV;
- goto end_init;
- }
-
- o_tty = NULL;
- tp = o_tp = NULL;
- ltp = o_ltp = NULL;
+ if (!try_module_get(driver->owner))
+ return ERR_PTR(-ENODEV);
tty = alloc_tty_struct();
if (!tty)
goto fail_no_mem;
- initialize_tty_struct(tty);
- tty->driver = driver;
- tty->ops = driver->ops;
- tty->index = idx;
- tty_line_name(driver, idx, tty->name);
-
- if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
- tp_loc = &tty->termios;
- ltp_loc = &tty->termios_locked;
- } else {
- tp_loc = &driver->termios[idx];
- ltp_loc = &driver->termios_locked[idx];
- }
-
- if (!*tp_loc) {
- tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
- if (!tp)
- goto free_mem_out;
- *tp = driver->init_termios;
- }
-
- if (!*ltp_loc) {
- ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
- if (!ltp)
- goto free_mem_out;
- }
-
- if (driver->type == TTY_DRIVER_TYPE_PTY) {
- o_tty = alloc_tty_struct();
- if (!o_tty)
- goto free_mem_out;
- initialize_tty_struct(o_tty);
- o_tty->driver = driver->other;
- o_tty->ops = driver->ops;
- o_tty->index = idx;
- tty_line_name(driver->other, idx, o_tty->name);
+ initialize_tty_struct(tty, driver, idx);
- if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
- o_tp_loc = &o_tty->termios;
- o_ltp_loc = &o_tty->termios_locked;
- } else {
- o_tp_loc = &driver->other->termios[idx];
- o_ltp_loc = &driver->other->termios_locked[idx];
- }
-
- if (!*o_tp_loc) {
- o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
- if (!o_tp)
- goto free_mem_out;
- *o_tp = driver->other->init_termios;
- }
-
- if (!*o_ltp_loc) {
- o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
- if (!o_ltp)
- goto free_mem_out;
- }
-
- /*
- * Everything allocated ... set up the o_tty structure.
- */
- if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM))
- driver->other->ttys[idx] = o_tty;
- if (!*o_tp_loc)
- *o_tp_loc = o_tp;
- if (!*o_ltp_loc)
- *o_ltp_loc = o_ltp;
- o_tty->termios = *o_tp_loc;
- o_tty->termios_locked = *o_ltp_loc;
- driver->other->refcount++;
- if (driver->subtype == PTY_TYPE_MASTER)
- o_tty->count++;
-
- /* Establish the links in both directions */
- tty->link = o_tty;
- o_tty->link = tty;
+ retval = tty_driver_install_tty(driver, tty);
+ if (retval < 0) {
+ free_tty_struct(tty);
+ module_put(driver->owner);
+ return ERR_PTR(retval);
}
/*
- * All structures have been allocated, so now we install them.
- * Failures after this point use release_tty to clean up, so
- * there's no need to null out the local pointers.
- */
- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM))
- driver->ttys[idx] = tty;
-
- if (!*tp_loc)
- *tp_loc = tp;
- if (!*ltp_loc)
- *ltp_loc = ltp;
- tty->termios = *tp_loc;
- tty->termios_locked = *ltp_loc;
- /* Compatibility until drivers always set this */
- tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
- tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
- driver->refcount++;
- tty->count++;
-
- /*
* Structures all installed ... call the ldisc open routines.
* If we fail here just call release_tty to clean up. No need
* to decrement the use counts, as release_tty doesn't care.
*/
- retval = tty_ldisc_setup(tty, o_tty);
-
+ retval = tty_ldisc_setup(tty, tty->link);
if (retval)
goto release_mem_out;
- goto success;
-
- /*
- * This fast open can be used if the tty is already open.
- * No memory is allocated, and the only failures are from
- * attempting to open a closing tty or attempting multiple
- * opens on a pty master.
- */
-fast_track:
- if (test_bit(TTY_CLOSING, &tty->flags)) {
- retval = -EIO;
- goto end_init;
- }
- if (driver->type == TTY_DRIVER_TYPE_PTY &&
- driver->subtype == PTY_TYPE_MASTER) {
- /*
- * special case for PTY masters: only one open permitted,
- * and the slave side open count is incremented as well.
- */
- if (tty->count) {
- retval = -EIO;
- goto end_init;
- }
- tty->link->count++;
- }
- tty->count++;
- tty->driver = driver; /* N.B. why do this every time?? */
-
- /* FIXME */
- if (!test_bit(TTY_LDISC, &tty->flags))
- printk(KERN_ERR "init_dev but no ldisc\n");
-success:
- *ret_tty = tty;
-
- /* All paths come through here to release the mutex */
-end_init:
- return retval;
-
- /* Release locally allocated memory ... nothing placed in slots */
-free_mem_out:
- kfree(o_tp);
- if (o_tty)
- free_tty_struct(o_tty);
- kfree(ltp);
- kfree(tp);
- free_tty_struct(tty);
+ return tty;
fail_no_mem:
module_put(driver->owner);
- retval = -ENOMEM;
- goto end_init;
+ return ERR_PTR(-ENOMEM);
/* call the tty release_tty routine to clean out this slot */
release_mem_out:
if (printk_ratelimit())
- printk(KERN_INFO "init_dev: ldisc open failed, "
+ printk(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx);
release_tty(tty, idx);
- goto end_init;
+ return ERR_PTR(retval);
}
+void tty_free_termios(struct tty_struct *tty)
+{
+ struct ktermios *tp;
+ int idx = tty->index;
+ /* Kill this flag and push into drivers for locking etc */
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+ /* FIXME: Locking on ->termios array */
+ tp = tty->termios;
+ tty->driver->termios[idx] = NULL;
+ kfree(tp);
+ }
+}
+EXPORT_SYMBOL(tty_free_termios);
+
+void tty_shutdown(struct tty_struct *tty)
+{
+ tty_driver_remove_tty(tty->driver, tty);
+ tty_free_termios(tty);
+}
+EXPORT_SYMBOL(tty_shutdown);
+
/**
* release_one_tty - release tty structure memory
+ * @kref: kref of tty we are obliterating
*
* Releases memory associated with a tty structure, and clears out the
* driver table slots. This function is called when a device is no longer
@@ -1863,31 +1455,19 @@ release_mem_out:
* tty_mutex - sometimes only
* takes the file list lock internally when working on the list
* of ttys that the driver keeps.
- * FIXME: should we require tty_mutex is held here ??
*/
-static void release_one_tty(struct tty_struct *tty, int idx)
+static void release_one_tty(struct kref *kref)
{
- int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
- struct ktermios *tp;
-
- if (!devpts)
- tty->driver->ttys[idx] = NULL;
-
- if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- tp = tty->termios;
- if (!devpts)
- tty->driver->termios[idx] = NULL;
- kfree(tp);
-
- tp = tty->termios_locked;
- if (!devpts)
- tty->driver->termios_locked[idx] = NULL;
- kfree(tp);
- }
-
+ struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+ struct tty_driver *driver = tty->driver;
+ if (tty->ops->shutdown)
+ tty->ops->shutdown(tty);
+ else
+ tty_shutdown(tty);
tty->magic = 0;
- tty->driver->refcount--;
+ tty_driver_kref_put(driver);
+ module_put(driver->owner);
file_list_lock();
list_del_init(&tty->tty_files);
@@ -1897,6 +1477,21 @@ static void release_one_tty(struct tty_struct *tty, int idx)
}
/**
+ * tty_kref_put - release a tty kref
+ * @tty: tty device
+ *
+ * Release a reference to a tty device and if need be let the kref
+ * layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+ if (tty)
+ kref_put(&tty->kref, release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
+/**
* release_tty - release tty structure memory
*
* Release both @tty and a possible linked partner (think pty pair),
@@ -1907,15 +1502,16 @@ static void release_one_tty(struct tty_struct *tty, int idx)
* takes the file list lock internally when working on the list
* of ttys that the driver keeps.
* FIXME: should we require tty_mutex is held here ??
+ *
*/
static void release_tty(struct tty_struct *tty, int idx)
{
- struct tty_driver *driver = tty->driver;
+ /* This should always be true but check for the moment */
+ WARN_ON(tty->index != idx);
if (tty->link)
- release_one_tty(tty->link, idx);
- release_one_tty(tty, idx);
- module_put(driver->owner);
+ tty_kref_put(tty->link);
+ tty_kref_put(tty);
}
/*
@@ -1926,20 +1522,21 @@ static void release_tty(struct tty_struct *tty, int idx)
* WSH 09/09/97: rewritten to avoid some nasty race conditions that could
* lead to double frees or releasing memory still in use.
*/
-static void release_dev(struct file *filp)
+void tty_release_dev(struct file *filp)
{
struct tty_struct *tty, *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep;
int devpts;
int idx;
char buf[64];
+ struct inode *inode;
+ inode = filp->f_path.dentry->d_inode;
tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
- "release_dev"))
+ if (tty_paranoia_check(tty, inode, "tty_release_dev"))
return;
- check_tty_count(tty, "release_dev");
+ check_tty_count(tty, "tty_release_dev");
tty_fasync(-1, filp, 0);
@@ -1951,33 +1548,27 @@ static void release_dev(struct file *filp)
#ifdef TTY_PARANOIA_CHECK
if (idx < 0 || idx >= tty->driver->num) {
- printk(KERN_DEBUG "release_dev: bad idx when trying to "
+ printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
"free (%s)\n", tty->name);
return;
}
- if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+ if (!devpts) {
if (tty != tty->driver->ttys[idx]) {
- printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
+ printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
"for (%s)\n", idx, tty->name);
return;
}
if (tty->termios != tty->driver->termios[idx]) {
- printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
+ printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
"for (%s)\n",
idx, tty->name);
return;
}
- if (tty->termios_locked != tty->driver->termios_locked[idx]) {
- printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
- "termios_locked for (%s)\n",
- idx, tty->name);
- return;
- }
}
#endif
#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
+ printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
tty_name(tty, buf), tty->count);
#endif
@@ -1985,26 +1576,19 @@ static void release_dev(struct file *filp)
if (tty->driver->other &&
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
if (o_tty != tty->driver->other->ttys[idx]) {
- printk(KERN_DEBUG "release_dev: other->table[%d] "
+ printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
"not o_tty for (%s)\n",
idx, tty->name);
return;
}
if (o_tty->termios != tty->driver->other->termios[idx]) {
- printk(KERN_DEBUG "release_dev: other->termios[%d] "
+ printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
"not o_termios for (%s)\n",
idx, tty->name);
return;
}
- if (o_tty->termios_locked !=
- tty->driver->other->termios_locked[idx]) {
- printk(KERN_DEBUG "release_dev: other->termios_locked["
- "%d] not o_termios_locked for (%s)\n",
- idx, tty->name);
- return;
- }
if (o_tty->link != tty) {
- printk(KERN_DEBUG "release_dev: bad pty pointers\n");
+ printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
return;
}
}
@@ -2062,7 +1646,7 @@ static void release_dev(struct file *filp)
if (!do_sleep)
break;
- printk(KERN_WARNING "release_dev: %s: read/write wait queue "
+ printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
"active!\n", tty_name(tty, buf));
mutex_unlock(&tty_mutex);
schedule();
@@ -2075,14 +1659,14 @@ static void release_dev(struct file *filp)
*/
if (pty_master) {
if (--o_tty->count < 0) {
- printk(KERN_WARNING "release_dev: bad pty slave count "
+ printk(KERN_WARNING "tty_release_dev: bad pty slave count "
"(%d) for %s\n",
o_tty->count, tty_name(o_tty, buf));
o_tty->count = 0;
}
}
if (--tty->count < 0) {
- printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
+ printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
tty->count, tty_name(tty, buf));
tty->count = 0;
}
@@ -2145,11 +1729,11 @@ static void release_dev(struct file *filp)
/* Make this pty number available for reallocation */
if (devpts)
- devpts_kill_index(idx);
+ devpts_kill_index(inode, idx);
}
/**
- * tty_open - open a tty device
+ * __tty_open - open a tty device
* @inode: inode of device file
* @filp: file pointer to tty
*
@@ -2164,14 +1748,14 @@ static void release_dev(struct file *filp)
* The termios state of a pty is reset on first open so that
* settings don't persist across reuse.
*
- * Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
+ * Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
* tty->count should protect the rest.
* ->siglock protects ->signal/->sighand
*/
static int __tty_open(struct inode *inode, struct file *filp)
{
- struct tty_struct *tty;
+ struct tty_struct *tty = NULL;
int noctty, retval;
struct tty_driver *driver;
int index;
@@ -2193,23 +1777,25 @@ retry_open:
mutex_unlock(&tty_mutex);
return -ENXIO;
}
- driver = tty->driver;
+ driver = tty_driver_kref_get(tty->driver);
index = tty->index;
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
/* noctty = 1; */
+ /* FIXME: Should we take a driver reference ? */
+ tty_kref_put(tty);
goto got_driver;
}
#ifdef CONFIG_VT
if (device == MKDEV(TTY_MAJOR, 0)) {
extern struct tty_driver *console_driver;
- driver = console_driver;
+ driver = tty_driver_kref_get(console_driver);
index = fg_console;
noctty = 1;
goto got_driver;
}
#endif
if (device == MKDEV(TTYAUX_MAJOR, 1)) {
- driver = console_device(&index);
+ driver = tty_driver_kref_get(console_device(&index));
if (driver) {
/* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK;
@@ -2226,10 +1812,25 @@ retry_open:
return -ENODEV;
}
got_driver:
- retval = init_dev(driver, index, &tty);
+ if (!tty) {
+ /* check whether we're reopening an existing tty */
+ tty = tty_driver_lookup_tty(driver, inode, index);
+
+ if (IS_ERR(tty))
+ return PTR_ERR(tty);
+ }
+
+ if (tty) {
+ retval = tty_reopen(tty);
+ if (retval)
+ tty = ERR_PTR(retval);
+ } else
+ tty = tty_init_dev(driver, index, 0);
+
mutex_unlock(&tty_mutex);
- if (retval)
- return retval;
+ tty_driver_kref_put(driver);
+ if (IS_ERR(tty))
+ return PTR_ERR(tty);
filp->private_data = tty;
file_move(filp, &tty->tty_files);
@@ -2257,7 +1858,7 @@ got_driver:
printk(KERN_DEBUG "error %d in opening %s...", retval,
tty->name);
#endif
- release_dev(filp);
+ tty_release_dev(filp);
if (retval != -ERESTARTSYS)
return retval;
if (signal_pending(current))
@@ -2296,69 +1897,6 @@ static int tty_open(struct inode *inode, struct file *filp)
-#ifdef CONFIG_UNIX98_PTYS
-/**
- * ptmx_open - open a unix 98 pty master
- * @inode: inode of device file
- * @filp: file pointer to tty
- *
- * Allocate a unix98 pty master device from the ptmx driver.
- *
- * Locking: tty_mutex protects theinit_dev work. tty->count should
- * protect the rest.
- * allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int __ptmx_open(struct inode *inode, struct file *filp)
-{
- struct tty_struct *tty;
- int retval;
- int index;
-
- nonseekable_open(inode, filp);
-
- /* find a device that is not in use. */
- index = devpts_new_index();
- if (index < 0)
- return index;
-
- mutex_lock(&tty_mutex);
- retval = init_dev(ptm_driver, index, &tty);
- mutex_unlock(&tty_mutex);
-
- if (retval)
- goto out;
-
- set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
- filp->private_data = tty;
- file_move(filp, &tty->tty_files);
-
- retval = devpts_pty_new(tty->link);
- if (retval)
- goto out1;
-
- check_tty_count(tty, "ptmx_open");
- retval = ptm_driver->ops->open(tty, filp);
- if (!retval)
- return 0;
-out1:
- release_dev(filp);
- return retval;
-out:
- devpts_kill_index(index);
- return retval;
-}
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
- int ret;
-
- lock_kernel();
- ret = __ptmx_open(inode, filp);
- unlock_kernel();
- return ret;
-}
-#endif
/**
* tty_release - vfs callback for close
@@ -2369,13 +1907,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
* this tty. There may however be several such references.
*
* Locking:
- * Takes bkl. See release_dev
+ * Takes bkl. See tty_release_dev
*/
static int tty_release(struct inode *inode, struct file *filp)
{
lock_kernel();
- release_dev(filp);
+ tty_release_dev(filp);
unlock_kernel();
return 0;
}
@@ -2524,7 +2062,7 @@ int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
/* For a PTY we need to lock the tty side */
mutex_lock(&real_tty->termios_mutex);
- if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+ if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
goto done;
/* Get the PID values and reference them so we can
avoid holding the tty ctrl lock while sending signals */
@@ -2996,7 +2534,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCSTI:
return tiocsti(tty, p);
case TIOCGWINSZ:
- return tiocgwinsz(tty, p);
+ return tiocgwinsz(real_tty, p);
case TIOCSWINSZ:
return tiocswinsz(tty, real_tty, p);
case TIOCCONS:
@@ -3026,10 +2564,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return put_user(tty->ldisc.ops->num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
-#ifdef CONFIG_VT
- case TIOCLINUX:
- return tioclinux(tty, arg);
-#endif
/*
* Break handling
*/
@@ -3220,113 +2754,6 @@ void do_SAK(struct tty_struct *tty)
EXPORT_SYMBOL(do_SAK);
/**
- * flush_to_ldisc
- * @work: tty structure passed from work queue.
- *
- * This routine is called out of the software interrupt to flush data
- * from the buffer chain to the line discipline.
- *
- * Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- * while invoking the line discipline receive_buf method. The
- * receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, buf.work.work);
- unsigned long flags;
- struct tty_ldisc *disc;
- struct tty_buffer *tbuf, *head;
- char *char_buf;
- unsigned char *flag_buf;
-
- disc = tty_ldisc_ref(tty);
- if (disc == NULL) /* !TTY_LDISC */
- return;
-
- spin_lock_irqsave(&tty->buf.lock, flags);
- /* So we know a flush is running */
- set_bit(TTY_FLUSHING, &tty->flags);
- head = tty->buf.head;
- if (head != NULL) {
- tty->buf.head = NULL;
- for (;;) {
- int count = head->commit - head->read;
- if (!count) {
- if (head->next == NULL)
- break;
- tbuf = head;
- head = head->next;
- tty_buffer_free(tty, tbuf);
- continue;
- }
- /* Ldisc or user is trying to flush the buffers
- we are feeding to the ldisc, stop feeding the
- line discipline as we want to empty the queue */
- if (test_bit(TTY_FLUSHPENDING, &tty->flags))
- break;
- if (!tty->receive_room) {
- schedule_delayed_work(&tty->buf.work, 1);
- break;
- }
- if (count > tty->receive_room)
- count = tty->receive_room;
- char_buf = head->char_buf_ptr + head->read;
- flag_buf = head->flag_buf_ptr + head->read;
- head->read += count;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
- disc->ops->receive_buf(tty, char_buf,
- flag_buf, count);
- spin_lock_irqsave(&tty->buf.lock, flags);
- }
- /* Restore the queue head */
- tty->buf.head = head;
- }
- /* We may have a deferred request to flush the input buffer,
- if so pull the chain under the lock and empty the queue */
- if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
- __tty_buffer_flush(tty);
- clear_bit(TTY_FLUSHPENDING, &tty->flags);
- wake_up(&tty->read_wait);
- }
- clear_bit(TTY_FLUSHING, &tty->flags);
- spin_unlock_irqrestore(&tty->buf.lock, flags);
-
- tty_ldisc_deref(disc);
-}
-
-/**
- * tty_flip_buffer_push - terminal
- * @tty: tty to push
- *
- * Queue a push of the terminal flip buffers to the line discipline. This
- * function must not be called from IRQ context if tty->low_latency is set.
- *
- * In the event of the queue being busy for flipping the work will be
- * held off and retried later.
- *
- * Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
- unsigned long flags;
- spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL)
- tty->buf.tail->commit = tty->buf.tail->used;
- spin_unlock_irqrestore(&tty->buf.lock, flags);
-
- if (tty->low_latency)
- flush_to_ldisc(&tty->buf.work.work);
- else
- schedule_delayed_work(&tty->buf.work, 1);
-}
-
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-
-/**
* initialize_tty_struct
* @tty: tty to initialize
*
@@ -3336,9 +2763,11 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
* Locking: none - tty in question must not be exposed at this point
*/
-static void initialize_tty_struct(struct tty_struct *tty)
+void initialize_tty_struct(struct tty_struct *tty,
+ struct tty_driver *driver, int idx)
{
memset(tty, 0, sizeof(struct tty_struct));
+ kref_init(&tty->kref);
tty->magic = TTY_MAGIC;
tty_ldisc_init(tty);
tty->session = NULL;
@@ -3346,7 +2775,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty->overrun_time = jiffies;
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
- INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
mutex_init(&tty->termios_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
@@ -3357,6 +2785,11 @@ static void initialize_tty_struct(struct tty_struct *tty)
spin_lock_init(&tty->ctrl_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
+
+ tty->driver = driver;
+ tty->ops = driver->ops;
+ tty->index = idx;
+ tty_line_name(driver, idx, tty->name);
}
/**
@@ -3377,10 +2810,9 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
return tty->ops->put_char(tty, ch);
return tty->ops->write(tty, &ch, 1);
}
-
EXPORT_SYMBOL_GPL(tty_put_char);
-static struct class *tty_class;
+struct class *tty_class;
/**
* tty_register_device - register a tty device
@@ -3420,6 +2852,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
return device_create_drvdata(tty_class, device, dev, NULL, name);
}
+EXPORT_SYMBOL(tty_register_device);
/**
* tty_unregister_device - unregister a tty device
@@ -3437,8 +2870,6 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
device_destroy(tty_class,
MKDEV(driver->major, driver->minor_start) + index);
}
-
-EXPORT_SYMBOL(tty_register_device);
EXPORT_SYMBOL(tty_unregister_device);
struct tty_driver *alloc_tty_driver(int lines)
@@ -3447,27 +2878,65 @@ struct tty_driver *alloc_tty_driver(int lines)
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
if (driver) {
+ kref_init(&driver->kref);
driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines;
/* later we'll move allocation of tables here */
}
return driver;
}
+EXPORT_SYMBOL(alloc_tty_driver);
-void put_tty_driver(struct tty_driver *driver)
+static void destruct_tty_driver(struct kref *kref)
{
+ struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
+ int i;
+ struct ktermios *tp;
+ void *p;
+
+ if (driver->flags & TTY_DRIVER_INSTALLED) {
+ /*
+ * Free the termios and termios_locked structures because
+ * we don't want to get memory leaks when modular tty
+ * drivers are removed from the kernel.
+ */
+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp) {
+ driver->termios[i] = NULL;
+ kfree(tp);
+ }
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+ tty_unregister_device(driver, i);
+ }
+ p = driver->ttys;
+ proc_tty_unregister_driver(driver);
+ driver->ttys = NULL;
+ driver->termios = NULL;
+ kfree(p);
+ cdev_del(&driver->cdev);
+ }
kfree(driver);
}
+void tty_driver_kref_put(struct tty_driver *driver)
+{
+ kref_put(&driver->kref, destruct_tty_driver);
+}
+EXPORT_SYMBOL(tty_driver_kref_put);
+
void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op)
{
driver->ops = op;
};
+EXPORT_SYMBOL(tty_set_operations);
-EXPORT_SYMBOL(alloc_tty_driver);
+void put_tty_driver(struct tty_driver *d)
+{
+ tty_driver_kref_put(d);
+}
EXPORT_SYMBOL(put_tty_driver);
-EXPORT_SYMBOL(tty_set_operations);
/*
* Called by a tty driver to register itself.
@@ -3479,11 +2948,8 @@ int tty_register_driver(struct tty_driver *driver)
dev_t dev;
void **p = NULL;
- if (driver->flags & TTY_DRIVER_INSTALLED)
- return 0;
-
if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
- p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+ p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
if (!p)
return -ENOMEM;
}
@@ -3507,12 +2973,9 @@ int tty_register_driver(struct tty_driver *driver)
if (p) {
driver->ttys = (struct tty_struct **)p;
driver->termios = (struct ktermios **)(p + driver->num);
- driver->termios_locked = (struct ktermios **)
- (p + driver->num * 2);
} else {
driver->ttys = NULL;
driver->termios = NULL;
- driver->termios_locked = NULL;
}
cdev_init(&driver->cdev, &tty_fops);
@@ -3521,7 +2984,7 @@ int tty_register_driver(struct tty_driver *driver)
if (error) {
unregister_chrdev_region(dev, driver->num);
driver->ttys = NULL;
- driver->termios = driver->termios_locked = NULL;
+ driver->termios = NULL;
kfree(p);
return error;
}
@@ -3535,6 +2998,7 @@ int tty_register_driver(struct tty_driver *driver)
tty_register_device(driver, i, NULL);
}
proc_tty_register_driver(driver);
+ driver->flags |= TTY_DRIVER_INSTALLED;
return 0;
}
@@ -3545,46 +3009,19 @@ EXPORT_SYMBOL(tty_register_driver);
*/
int tty_unregister_driver(struct tty_driver *driver)
{
- int i;
- struct ktermios *tp;
- void *p;
-
+#if 0
+ /* FIXME */
if (driver->refcount)
return -EBUSY;
-
+#endif
unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
driver->num);
mutex_lock(&tty_mutex);
list_del(&driver->tty_drivers);
mutex_unlock(&tty_mutex);
-
- /*
- * Free the termios and termios_locked structures because
- * we don't want to get memory leaks when modular tty
- * drivers are removed from the kernel.
- */
- for (i = 0; i < driver->num; i++) {
- tp = driver->termios[i];
- if (tp) {
- driver->termios[i] = NULL;
- kfree(tp);
- }
- tp = driver->termios_locked[i];
- if (tp) {
- driver->termios_locked[i] = NULL;
- kfree(tp);
- }
- if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
- tty_unregister_device(driver, i);
- }
- p = driver->ttys;
- proc_tty_unregister_driver(driver);
- driver->ttys = NULL;
- driver->termios = driver->termios_locked = NULL;
- kfree(p);
- cdev_del(&driver->cdev);
return 0;
}
+
EXPORT_SYMBOL(tty_unregister_driver);
dev_t tty_devnum(struct tty_struct *tty)
@@ -3595,9 +3032,12 @@ EXPORT_SYMBOL(tty_devnum);
void proc_clear_tty(struct task_struct *p)
{
+ struct tty_struct *tty;
spin_lock_irq(&p->sighand->siglock);
+ tty = p->signal->tty;
p->signal->tty = NULL;
spin_unlock_irq(&p->sighand->siglock);
+ tty_kref_put(tty);
}
/* Called under the sighand lock */
@@ -3613,9 +3053,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
tty->pgrp = get_pid(task_pgrp(tsk));
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
tty->session = get_pid(task_session(tsk));
+ if (tsk->signal->tty) {
+ printk(KERN_DEBUG "tty not NULL!!\n");
+ tty_kref_put(tsk->signal->tty);
+ }
}
put_pid(tsk->signal->tty_old_pgrp);
- tsk->signal->tty = tty;
+ tsk->signal->tty = tty_kref_get(tty);
tsk->signal->tty_old_pgrp = NULL;
}
@@ -3629,18 +3073,20 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
struct tty_struct *get_current_tty(void)
{
struct tty_struct *tty;
- WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
- tty = current->signal->tty;
- /*
- * session->tty can be changed/cleared from under us, make sure we
- * issue the load. The obtained pointer, when not NULL, is valid as
- * long as we hold tty_mutex.
- */
- barrier();
+ unsigned long flags;
+
+ spin_lock_irqsave(&current->sighand->siglock, flags);
+ tty = tty_kref_get(current->signal->tty);
+ spin_unlock_irqrestore(&current->sighand->siglock, flags);
return tty;
}
EXPORT_SYMBOL_GPL(get_current_tty);
+void tty_default_fops(struct file_operations *fops)
+{
+ *fops = tty_fops;
+}
+
/*
* Initialize the console device. This is called *early*, so
* we can't necessarily depend on lots of kernel help here.
@@ -3678,12 +3124,6 @@ postcore_initcall(tty_class_init);
/* 3/2004 jmc: why do these devices exist? */
static struct cdev tty_cdev, console_cdev;
-#ifdef CONFIG_UNIX98_PTYS
-static struct cdev ptmx_cdev;
-#endif
-#ifdef CONFIG_VT
-static struct cdev vc0_cdev;
-#endif
/*
* Ok, now we can initialize the rest of the tty devices and can count
@@ -3695,32 +3135,18 @@ static int __init tty_init(void)
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
panic("Couldn't register /dev/tty driver\n");
- device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+ device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
"tty");
cdev_init(&console_cdev, &console_fops);
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n");
- device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+ device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
"console");
-#ifdef CONFIG_UNIX98_PTYS
- cdev_init(&ptmx_cdev, &ptmx_fops);
- if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
- register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
- panic("Couldn't register /dev/ptmx driver\n");
- device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-#endif
-
#ifdef CONFIG_VT
- cdev_init(&vc0_cdev, &console_fops);
- if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
- register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
- panic("Couldn't register /dev/tty0 driver\n");
- device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
- vty_init();
+ vty_init(&console_fops);
#endif
return 0;
}
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index bf34e459742..a408c8e487e 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -40,6 +40,15 @@
#define TERMIOS_OLD 8
+/**
+ * tty_chars_in_buffer - characters pending
+ * @tty: terminal
+ *
+ * Return the number of bytes of data in the device private
+ * output queue. If no private method is supplied there is assumed
+ * to be no queue on the device.
+ */
+
int tty_chars_in_buffer(struct tty_struct *tty)
{
if (tty->ops->chars_in_buffer)
@@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty)
else
return 0;
}
-
EXPORT_SYMBOL(tty_chars_in_buffer);
+/**
+ * tty_write_room - write queue space
+ * @tty: terminal
+ *
+ * Return the number of bytes that can be queued to this device
+ * at the present time. The result should be treated as a guarantee
+ * and the driver cannot offer a value it later shrinks by more than
+ * the number of bytes written. If no method is provided 2K is always
+ * returned and data may be lost as there will be no flow control.
+ */
+
int tty_write_room(struct tty_struct *tty)
{
if (tty->ops->write_room)
return tty->ops->write_room(tty);
return 2048;
}
-
EXPORT_SYMBOL(tty_write_room);
+/**
+ * tty_driver_flush_buffer - discard internal buffer
+ * @tty: terminal
+ *
+ * Discard the internal output buffer for this device. If no method
+ * is provided then either the buffer cannot be hardware flushed or
+ * there is no buffer driver side.
+ */
void tty_driver_flush_buffer(struct tty_struct *tty)
{
if (tty->ops->flush_buffer)
tty->ops->flush_buffer(tty);
}
-
EXPORT_SYMBOL(tty_driver_flush_buffer);
+/**
+ * tty_throttle - flow control
+ * @tty: terminal
+ *
+ * Indicate that a tty should stop transmitting data down the stack.
+ */
+
void tty_throttle(struct tty_struct *tty)
{
/* check TTY_THROTTLED first so it indicates our state */
@@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_throttle);
+/**
+ * tty_unthrottle - flow control
+ * @tty: terminal
+ *
+ * Indicate that a tty may continue transmitting data down the stack.
+ */
+
void tty_unthrottle(struct tty_struct *tty)
{
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
@@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
}
EXPORT_SYMBOL(tty_wait_until_sent);
+
+/*
+ * Termios Helper Methods
+ */
+
static void unset_locked_termios(struct ktermios *termios,
struct ktermios *old,
struct ktermios *locked)
@@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
}
EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
+/**
+ * tty_encode_baud_rate - set baud rate of the tty
+ * @ibaud: input baud rate
+ * @obad: output baud rate
+ *
+ * Update the current termios data for the tty with the new speed
+ * settings. The caller must hold the termios_mutex for the tty in
+ * question.
+ */
+
void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
{
tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
@@ -430,12 +484,11 @@ EXPORT_SYMBOL(tty_termios_hw_change);
* is a bit of layering violation here with n_tty in terms of the
* internal knowledge of this function.
*
- * Locking: termios_sem
+ * Locking: termios_mutex
*/
static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
- int canon_change;
struct ktermios old_termios;
struct tty_ldisc *ld;
unsigned long flags;
@@ -451,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
old_termios = *tty->termios;
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
- canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
- if (canon_change) {
- memset(&tty->read_flags, 0, sizeof tty->read_flags);
- tty->canon_head = tty->read_tail;
- tty->canon_data = 0;
- tty->erasing = 0;
- }
-
- /* This bit should be in the ldisc code */
- if (canon_change && !L_ICANON(tty) && tty->read_cnt)
- /* Get characters left over from canonical mode. */
- wake_up_interruptible(&tty->read_wait);
/* See if packet mode change of state. */
if (tty->link && tty->link->packet) {
@@ -508,7 +549,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
* functions before using change_termios to do the actual changes.
*
* Locking:
- * Called functions take ldisc and termios_sem locks
+ * Called functions take ldisc and termios_mutex locks
*/
static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@@ -579,25 +620,51 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio)
return 0;
}
-static unsigned long inq_canon(struct tty_struct *tty)
+
+#ifdef TCGETX
+
+/**
+ * set_termiox - set termiox fields if possible
+ * @tty: terminal
+ * @arg: termiox structure from user
+ * @opt: option flags for ioctl type
+ *
+ * Implement the device calling points for the SYS5 termiox ioctl
+ * interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
{
- int nr, head, tail;
+ struct termiox tnew;
+ struct tty_ldisc *ld;
- if (!tty->canon_data || !tty->read_buf)
- return 0;
- head = tty->canon_head;
- tail = tty->read_tail;
- nr = (head - tail) & (N_TTY_BUF_SIZE-1);
- /* Skip EOF-chars.. */
- while (head != tail) {
- if (test_bit(tail, tty->read_flags) &&
- tty->read_buf[tail] == __DISABLED_CHAR)
- nr--;
- tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+ if (tty->termiox == NULL)
+ return -EINVAL;
+ if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+ return -EFAULT;
+
+ ld = tty_ldisc_ref(tty);
+ if (ld != NULL) {
+ if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+ ld->ops->flush_buffer(tty);
+ tty_ldisc_deref(ld);
}
- return nr;
+ if (opt & TERMIOS_WAIT) {
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+
+ mutex_lock(&tty->termios_mutex);
+ if (tty->ops->set_termiox)
+ tty->ops->set_termiox(tty, &tnew);
+ mutex_unlock(&tty->termios_mutex);
+ return 0;
}
+#endif
+
+
#ifdef TIOCGETP
/*
* These are deprecated, but there is limited support..
@@ -671,7 +738,7 @@ static void set_sgflags(struct ktermios *termios, int flags)
* Updates a terminal from the legacy BSD style terminal information
* structure.
*
- * Locking: termios_sem
+ * Locking: termios_mutex
*/
static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
@@ -849,6 +916,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
{
struct tty_struct *real_tty;
void __user *p = (void __user *)arg;
+ int ret = 0;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -884,18 +952,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termios(real_tty, p, TERMIOS_OLD);
#ifndef TCGETS2
case TCGETS:
+ mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
#else
case TCGETS:
+ mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
case TCGETS2:
+ mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
case TCSETSF2:
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
case TCSETSW2:
@@ -913,34 +987,59 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termios(real_tty, p, TERMIOS_TERMIO);
#ifndef TCGETS2
case TIOCGLCKTRMIOS:
+ mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ mutex_lock(&real_tty->termios_mutex);
if (user_termios_to_kernel_termios(real_tty->termios_locked,
(struct termios __user *) arg))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
#else
case TIOCGLCKTRMIOS:
+ mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
+ ret = -EPERM;
+ mutex_lock(&real_tty->termios_mutex);
if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
(struct termios __user *) arg))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
#endif
+#ifdef TCGETX
+ case TCGETX:
+ if (real_tty->termiox == NULL)
+ return -EINVAL;
+ mutex_lock(&real_tty->termios_mutex);
+ if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
+ ret = -EFAULT;
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
+ case TCSETX:
+ return set_termiox(real_tty, p, 0);
+ case TCSETXW:
+ return set_termiox(real_tty, p, TERMIOS_WAIT);
+ case TCSETXF:
+ return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif
case TIOCGSOFTCAR:
- /* FIXME: for correctness we may need to take the termios
- lock here - review */
- return put_user(C_CLOCAL(real_tty) ? 1 : 0,
+ mutex_lock(&real_tty->termios_mutex);
+ ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
(int __user *)arg);
+ mutex_unlock(&real_tty->termios_mutex);
+ return ret;
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
@@ -980,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
}
EXPORT_SYMBOL_GPL(tty_perform_flush);
-int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned long flags;
@@ -1018,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return 0;
case TCFLSH:
return tty_perform_flush(tty, arg);
- case TIOCOUTQ:
- return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
- case TIOCINQ:
- retval = tty->read_cnt;
- if (L_ICANON(tty))
- retval = inq_canon(tty);
- return put_user(retval, (unsigned int __user *) arg);
case TIOCPKT:
{
int pktmode;
@@ -1050,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return tty_mode_ioctl(tty, file, cmd, arg);
}
}
-EXPORT_SYMBOL(n_tty_ioctl);
+EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
new file mode 100644
index 00000000000..553b0e9d8d1
--- /dev/null
+++ b/drivers/char/tty_port.c
@@ -0,0 +1,96 @@
+/*
+ * Tty port functions
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+void tty_port_init(struct tty_port *port)
+{
+ memset(port, 0, sizeof(*port));
+ init_waitqueue_head(&port->open_wait);
+ init_waitqueue_head(&port->close_wait);
+ mutex_init(&port->mutex);
+ spin_lock_init(&port->lock);
+ port->close_delay = (50 * HZ) / 100;
+ port->closing_wait = (3000 * HZ) / 100;
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+ /* We may sleep in get_zeroed_page() */
+ mutex_lock(&port->mutex);
+ if (port->xmit_buf == NULL)
+ port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+ mutex_unlock(&port->mutex);
+ if (port->xmit_buf == NULL)
+ return -ENOMEM;
+ return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+ mutex_lock(&port->mutex);
+ if (port->xmit_buf != NULL) {
+ free_page((unsigned long)port->xmit_buf);
+ port->xmit_buf = NULL;
+ }
+ mutex_unlock(&port->mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+
+/**
+ * tty_port_tty_get - get a tty reference
+ * @port: tty port
+ *
+ * Return a refcount protected tty instance or NULL if the port is not
+ * associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+ unsigned long flags;
+ struct tty_struct *tty;
+
+ spin_lock_irqsave(&port->lock, flags);
+ tty = tty_kref_get(port->tty);
+ spin_unlock_irqrestore(&port->lock, flags);
+ return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ * tty_port_tty_set - set the tty of a port
+ * @port: tty port
+ * @tty: the tty
+ *
+ * Associate the port and tty pair. Manages any internal refcounts.
+ * Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (port->tty)
+ tty_kref_put(port->tty);
+ port->tty = tty;
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 60359c36091..57029fefd64 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -100,10 +100,10 @@
#include <linux/font.h>
#include <linux/bitops.h>
#include <linux/notifier.h>
-
-#include <asm/io.h>
+#include <linux/device.h>
+#include <linux/io.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#define MAX_NR_CON_DRIVER 16
@@ -2136,27 +2136,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
release_console_sem();
return 0;
}
- release_console_sem();
-
orig_buf = buf;
orig_count = count;
- /* At this point 'buf' is guaranteed to be a kernel buffer
- * and therefore no access to userspace (and therefore sleeping)
- * will be needed. The con_buf_mtx serializes all tty based
- * console rendering and vcs write/read operations. We hold
- * the console spinlock during the entire write.
- */
-
- acquire_console_sem();
-
- vc = tty->driver_data;
- if (vc == NULL) {
- printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
- release_console_sem();
- goto out;
- }
-
himask = vc->vc_hi_font_mask;
charmask = himask ? 0x1ff : 0xff;
@@ -2370,8 +2352,6 @@ rescan_last_byte:
FLUSH
console_conditional_schedule();
release_console_sem();
-
-out:
notify_update(vc);
return n;
#undef FLUSH
@@ -2583,8 +2563,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
int lines;
int ret;
- if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
- return -EINVAL;
if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
return -EPERM;
if (get_user(type, p))
@@ -2778,6 +2756,12 @@ static int con_open(struct tty_struct *tty, struct file *filp)
ret = vc_allocate(currcons);
if (ret == 0) {
struct vc_data *vc = vc_cons[currcons].d;
+
+ /* Still being freed */
+ if (vc->vc_tty) {
+ release_console_sem();
+ return -ERESTARTSYS;
+ }
tty->driver_data = vc;
vc->vc_tty = tty;
@@ -2798,34 +2782,20 @@ static int con_open(struct tty_struct *tty, struct file *filp)
return ret;
}
-/*
- * We take tty_mutex in here to prevent another thread from coming in via init_dev
- * and taking a ref against the tty while we're in the process of forgetting
- * about it and cleaning things up.
- *
- * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
- */
static void con_close(struct tty_struct *tty, struct file *filp)
{
- mutex_lock(&tty_mutex);
- acquire_console_sem();
- if (tty && tty->count == 1) {
- struct vc_data *vc = tty->driver_data;
+ /* Nothing to do - we defer to shutdown */
+}
- if (vc)
- vc->vc_tty = NULL;
- tty->driver_data = NULL;
- vcs_remove_sysfs(tty);
- release_console_sem();
- mutex_unlock(&tty_mutex);
- /*
- * tty_mutex is released, but we still hold BKL, so there is
- * still exclusion against init_dev()
- */
- return;
- }
+static void con_shutdown(struct tty_struct *tty)
+{
+ struct vc_data *vc = tty->driver_data;
+ BUG_ON(vc == NULL);
+ acquire_console_sem();
+ vc->vc_tty = NULL;
+ vcs_remove_sysfs(tty);
release_console_sem();
- mutex_unlock(&tty_mutex);
+ tty_shutdown(tty);
}
static int default_italic_color = 2; // green (ASCII)
@@ -2950,10 +2920,19 @@ static const struct tty_operations con_ops = {
.throttle = con_throttle,
.unthrottle = con_unthrottle,
.resize = vt_resize,
+ .shutdown = con_shutdown
};
-int __init vty_init(void)
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
{
+ cdev_init(&vc0_cdev, console_fops);
+ if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+ register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+ panic("Couldn't register /dev/tty0 driver\n");
+ device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
vcs_init();
console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
@@ -2972,7 +2951,6 @@ int __init vty_init(void)
tty_set_operations(console_driver, &con_ops);
if (tty_register_driver(console_driver))
panic("Couldn't register console driver\n");
-
kbd_init();
console_map_init();
#ifdef CONFIG_PROM_CONSOLE
@@ -3466,7 +3444,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
if (retval)
goto err;
- con_driver->dev = device_create_drvdata(vtconsole_class, NULL,
+ con_driver->dev = device_create(vtconsole_class, NULL,
MKDEV(0, con_driver->node),
NULL, "vtcon%i",
con_driver->node);
@@ -3577,7 +3555,7 @@ static int __init vtconsole_class_init(void)
struct con_driver *con = &registered_con_driver[i];
if (con->con && !con->dev) {
- con->dev = device_create_drvdata(vtconsole_class, NULL,
+ con->dev = device_create(vtconsole_class, NULL,
MKDEV(0, con->node),
NULL, "vtcon%i",
con->node);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index c904e9ad4a7..8944ce508e2 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -395,6 +395,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
kbd = kbd_table + console;
switch (cmd) {
+ case TIOCLINUX:
+ return tioclinux(tty, arg);
case KIOCSOUND:
if (!perm)
goto eperm;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 3309e862f31..ebacc0af40f 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -800,6 +800,13 @@ config SENSORS_W83627EHF
This driver can also be built as a module. If so, the module
will be called w83627ehf.
+config SENSORS_ULTRA45
+ tristate "Sun Ultra45 PIC16F747"
+ depends on SPARC64
+ help
+ This driver provides support for the Ultra45 workstation environmental
+ sensors.
+
config SENSORS_HDAPS
tristate "IBM Hard Drive Active Protection System (hdaps)"
depends on INPUT && X86
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 6babc801b34..042d5a78622 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
+obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
new file mode 100644
index 00000000000..68e90abeba9
--- /dev/null
+++ b/drivers/hwmon/ultra45_env.c
@@ -0,0 +1,320 @@
+/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#define DRV_MODULE_VERSION "0.1"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Ultra45 environmental monitor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+/* PIC device registers */
+#define REG_CMD 0x00UL
+#define REG_CMD_RESET 0x80
+#define REG_CMD_ESTAR 0x01
+#define REG_STAT 0x01UL
+#define REG_STAT_FWVER 0xf0
+#define REG_STAT_TGOOD 0x08
+#define REG_STAT_STALE 0x04
+#define REG_STAT_BUSY 0x02
+#define REG_STAT_FAULT 0x01
+#define REG_DATA 0x40UL
+#define REG_ADDR 0x41UL
+#define REG_SIZE 0x42UL
+
+/* Registers accessed indirectly via REG_DATA/REG_ADDR */
+#define IREG_FAN0 0x00
+#define IREG_FAN1 0x01
+#define IREG_FAN2 0x02
+#define IREG_FAN3 0x03
+#define IREG_FAN4 0x04
+#define IREG_FAN5 0x05
+#define IREG_LCL_TEMP 0x06
+#define IREG_RMT1_TEMP 0x07
+#define IREG_RMT2_TEMP 0x08
+#define IREG_RMT3_TEMP 0x09
+#define IREG_LM95221_TEMP 0x0a
+#define IREG_FIRE_TEMP 0x0b
+#define IREG_LSI1064_TEMP 0x0c
+#define IREG_FRONT_TEMP 0x0d
+#define IREG_FAN_STAT 0x0e
+#define IREG_VCORE0 0x0f
+#define IREG_VCORE1 0x10
+#define IREG_VMEM0 0x11
+#define IREG_VMEM1 0x12
+#define IREG_PSU_TEMP 0x13
+
+struct env {
+ void __iomem *regs;
+ spinlock_t lock;
+
+ struct device *hwmon_dev;
+};
+
+static u8 env_read(struct env *p, u8 ireg)
+{
+ u8 ret;
+
+ spin_lock(&p->lock);
+ writeb(ireg, p->regs + REG_ADDR);
+ ret = readb(p->regs + REG_DATA);
+ spin_unlock(&p->lock);
+
+ return ret;
+}
+
+static void env_write(struct env *p, u8 ireg, u8 val)
+{
+ spin_lock(&p->lock);
+ writeb(ireg, p->regs + REG_ADDR);
+ writeb(val, p->regs + REG_DATA);
+ spin_unlock(&p->lock);
+}
+
+/* There seems to be a adr7462 providing these values, thus a lot
+ * of these calculations are borrowed from the adt7470 driver.
+ */
+#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID (0xff << 8)
+#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
+
+static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int fan_nr = to_sensor_dev_attr(attr)->index;
+ struct env *p = dev_get_drvdata(dev);
+ int rpm, period;
+ u8 val;
+
+ val = env_read(p, IREG_FAN0 + fan_nr);
+ period = (int) val << 8;
+ if (FAN_DATA_VALID(period))
+ rpm = FAN_PERIOD_TO_RPM(period);
+ else
+ rpm = 0;
+
+ return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int fan_nr = to_sensor_dev_attr(attr)->index;
+ int rpm = simple_strtol(buf, NULL, 10);
+ struct env *p = dev_get_drvdata(dev);
+ int period;
+ u8 val;
+
+ if (!rpm)
+ return -EINVAL;
+
+ period = FAN_RPM_TO_PERIOD(rpm);
+ val = period >> 8;
+ env_write(p, IREG_FAN0 + fan_nr, val);
+
+ return count;
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int fan_nr = to_sensor_dev_attr(attr)->index;
+ struct env *p = dev_get_drvdata(dev);
+ u8 val = env_read(p, IREG_FAN_STAT);
+ return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
+}
+
+#define fan(index) \
+static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR, \
+ show_fan_speed, set_fan_speed, index); \
+static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, \
+ show_fan_fault, NULL, index)
+
+fan(0);
+fan(1);
+fan(2);
+fan(3);
+fan(4);
+
+static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6);
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int temp_nr = to_sensor_dev_attr(attr)->index;
+ struct env *p = dev_get_drvdata(dev);
+ s8 val;
+
+ val = env_read(p, IREG_LCL_TEMP + temp_nr);
+ return sprintf(buf, "%d\n", ((int) val) - 64);
+}
+
+static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13);
+
+static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct env *p = dev_get_drvdata(dev);
+ u8 val;
+
+ val = readb(p->regs + REG_STAT);
+ return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0);
+static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1);
+static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2);
+static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3);
+
+static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct env *p = dev_get_drvdata(dev);
+ u8 val;
+
+ val = readb(p->regs + REG_STAT);
+ return sprintf(buf, "%d\n", val >> 4);
+}
+
+static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0);
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "ultra45\n");
+}
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static struct attribute *env_attributes[] = {
+ &sensor_dev_attr_fan0_speed.dev_attr.attr,
+ &sensor_dev_attr_fan0_fault.dev_attr.attr,
+ &sensor_dev_attr_fan1_speed.dev_attr.attr,
+ &sensor_dev_attr_fan1_fault.dev_attr.attr,
+ &sensor_dev_attr_fan2_speed.dev_attr.attr,
+ &sensor_dev_attr_fan2_fault.dev_attr.attr,
+ &sensor_dev_attr_fan3_speed.dev_attr.attr,
+ &sensor_dev_attr_fan3_fault.dev_attr.attr,
+ &sensor_dev_attr_fan4_speed.dev_attr.attr,
+ &sensor_dev_attr_fan4_fault.dev_attr.attr,
+ &sensor_dev_attr_psu_fan_fault.dev_attr.attr,
+ &sensor_dev_attr_adt7462_local_temp.dev_attr.attr,
+ &sensor_dev_attr_cpu0_temp.dev_attr.attr,
+ &sensor_dev_attr_cpu1_temp.dev_attr.attr,
+ &sensor_dev_attr_motherboard_temp.dev_attr.attr,
+ &sensor_dev_attr_lm95221_local_temp.dev_attr.attr,
+ &sensor_dev_attr_fire_temp.dev_attr.attr,
+ &sensor_dev_attr_lsi1064_local_temp.dev_attr.attr,
+ &sensor_dev_attr_front_panel_temp.dev_attr.attr,
+ &sensor_dev_attr_psu_temp.dev_attr.attr,
+ &sensor_dev_attr_fan_failure.dev_attr.attr,
+ &sensor_dev_attr_env_bus_busy.dev_attr.attr,
+ &sensor_dev_attr_env_data_stale.dev_attr.attr,
+ &sensor_dev_attr_tpm_self_test_passed.dev_attr.attr,
+ &sensor_dev_attr_firmware_version.dev_attr.attr,
+ &sensor_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group env_group = {
+ .attrs = env_attributes,
+};
+
+static int __devinit env_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct env *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
+
+ if (!p)
+ goto out;
+
+ spin_lock_init(&p->lock);
+
+ p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
+ if (!p->regs)
+ goto out_free;
+
+ err = sysfs_create_group(&op->dev.kobj, &env_group);
+ if (err)
+ goto out_iounmap;
+
+ p->hwmon_dev = hwmon_device_register(&op->dev);
+ if (IS_ERR(p->hwmon_dev)) {
+ err = PTR_ERR(p->hwmon_dev);
+ goto out_sysfs_remove_group;
+ }
+
+ dev_set_drvdata(&op->dev, p);
+ err = 0;
+
+out:
+ return err;
+
+out_sysfs_remove_group:
+ sysfs_remove_group(&op->dev.kobj, &env_group);
+
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+
+out_free:
+ kfree(p);
+ goto out;
+}
+
+static int __devexit env_remove(struct of_device *op)
+{
+ struct env *p = dev_get_drvdata(&op->dev);
+
+ if (p) {
+ sysfs_remove_group(&op->dev.kobj, &env_group);
+ hwmon_device_unregister(p->hwmon_dev);
+ of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+ kfree(p);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id env_match[] = {
+ {
+ .name = "env-monitor",
+ .compatible = "SUNW,ebus-pic16f747-env",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, env_match);
+
+static struct of_platform_driver env_driver = {
+ .name = "ultra45_env",
+ .match_table = env_match,
+ .probe = env_probe,
+ .remove = __devexit_p(env_remove),
+};
+
+static int __init env_init(void)
+{
+ return of_register_driver(&env_driver, &of_bus_type);
+}
+
+static void __exit env_exit(void)
+{
+ of_unregister_driver(&env_driver);
+}
+
+module_init(env_init);
+module_exit(env_exit);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index ed7c5f72cb8..5b8b533f290 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1683,7 +1683,7 @@ enum {
SRP_OPT_SERVICE_ID),
};
-static match_table_t srp_opt_tokens = {
+static const match_table_t srp_opt_tokens = {
{ SRP_OPT_ID_EXT, "id_ext=%s" },
{ SRP_OPT_IOC_GUID, "ioc_guid=%s" },
{ SRP_OPT_DGID, "dgid=%s" },
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index d8765cc93d2..c4f42311fde 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -249,7 +249,7 @@ static int bbc_remove(struct of_device *op)
return 0;
}
-static struct of_device_id bbc_beep_match[] = {
+static const struct of_device_id bbc_beep_match[] = {
{
.name = "beep",
.compatible = "SUNW,bbc-beep",
@@ -328,7 +328,7 @@ static int grover_remove(struct of_device *op)
return 0;
}
-static struct of_device_id grover_beep_match[] = {
+static const struct of_device_id grover_beep_match[] = {
{
.name = "beep",
.compatible = "SUNW,smbus-beep",
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index 692a79ec2a2..5071af2c060 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -87,7 +87,7 @@ static int __devexit sparc_i8042_remove(struct of_device *op)
return 0;
}
-static struct of_device_id sparc_i8042_match[] = {
+static const struct of_device_id sparc_i8042_match[] = {
{
.name = "8042",
},
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index 9ce3b3baf3a..3ab6362f043 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -335,11 +335,11 @@ static struct xenbus_driver xenkbd = {
static int __init xenkbd_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
/* Nothing to do if running in dom0. */
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return -ENODEV;
return xenbus_register_frontend(&xenkbd);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 871b0cbca5e..798d7f3e42e 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1231,7 +1231,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
int error = 0;
switch (cmd) {
default:
- error = n_tty_ioctl (tty, file, cmd, arg);
+ error = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
}
return error;
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 5e89fa17781..07052ed2a0c 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -571,6 +571,7 @@ gigaset_tty_close(struct tty_struct *tty)
}
/* prevent other callers from entering ldisc methods */
+ /* FIXME: should use the tty state flags */
tty->disc_data = NULL;
if (!cs->hw.ser)
@@ -642,10 +643,11 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
return -ENXIO;
switch (cmd) {
- case TCGETS:
- case TCGETA:
- /* pass through to underlying serial device */
- rc = n_tty_ioctl(tty, file, cmd, arg);
+
+ case FIONREAD:
+ /* unused, always return zero */
+ val = 0;
+ rc = put_user(val, p);
break;
case TCFLSH:
@@ -659,20 +661,13 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
flush_send_queue(cs);
break;
}
- /* flush the serial port's buffer */
- rc = n_tty_ioctl(tty, file, cmd, arg);
- break;
-
- case FIONREAD:
- /* unused, always return zero */
- val = 0;
- rc = put_user(val, p);
- break;
+ /* Pass through */
default:
- rc = -ENOIOCTLCMD;
+ /* pass through to underlying serial device */
+ rc = n_tty_ioctl_helper(tty, file, cmd, arg);
+ break;
}
-
cs_put(cs);
return rc;
}
@@ -680,6 +675,8 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
/*
* Poll on the tty.
* Unused, always return zero.
+ *
+ * FIXME: should probably return an exception - especially on hangup
*/
static unsigned int
gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 5b14262af01..e3e40427e00 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -82,6 +82,14 @@ config LEDS_COBALT_RAQ
help
This option enables support for the Cobalt Raq series LEDs.
+config LEDS_SUNFIRE
+ tristate "LED support for SunFire servers."
+ depends on LEDS_CLASS && SPARC64
+ select LEDS_TRIGGERS
+ help
+ This option enables support for the Left, Middle, and Right
+ LEDs on the I/O and CPU boards of SunFire UltraSPARC servers.
+
config LEDS_HP6XX
tristate "LED Support for the HP Jornada 6xx"
depends on LEDS_CLASS && SH_HP6XX
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 3a8e6a04363..eb186c351a1 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
+obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
new file mode 100644
index 00000000000..6b008f0c3f6
--- /dev/null
+++ b/drivers/leds/leds-sunfire.c
@@ -0,0 +1,273 @@
+/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/fhc.h>
+#include <asm/upa.h>
+
+#define DRIVER_NAME "leds-sunfire"
+#define PFX DRIVER_NAME ": "
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun Fire LED driver");
+MODULE_LICENSE("GPL");
+
+struct sunfire_led {
+ struct led_classdev led_cdev;
+ void __iomem *reg;
+};
+#define to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev)
+
+static void __clockboard_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val, u8 bit)
+{
+ struct sunfire_led *p = to_sunfire_led(led_cdev);
+ u8 reg = upa_readb(p->reg);
+
+ switch (bit) {
+ case CLOCK_CTRL_LLED:
+ if (led_val)
+ reg &= ~bit;
+ else
+ reg |= bit;
+ break;
+
+ default:
+ if (led_val)
+ reg |= bit;
+ else
+ reg &= ~bit;
+ break;
+ }
+ upa_writeb(reg, p->reg);
+}
+
+static void clockboard_left_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val)
+{
+ __clockboard_set(led_cdev, led_val, CLOCK_CTRL_LLED);
+}
+
+static void clockboard_middle_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val)
+{
+ __clockboard_set(led_cdev, led_val, CLOCK_CTRL_MLED);
+}
+
+static void clockboard_right_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val)
+{
+ __clockboard_set(led_cdev, led_val, CLOCK_CTRL_RLED);
+}
+
+static void __fhc_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val, u32 bit)
+{
+ struct sunfire_led *p = to_sunfire_led(led_cdev);
+ u32 reg = upa_readl(p->reg);
+
+ switch (bit) {
+ case FHC_CONTROL_LLED:
+ if (led_val)
+ reg &= ~bit;
+ else
+ reg |= bit;
+ break;
+
+ default:
+ if (led_val)
+ reg |= bit;
+ else
+ reg &= ~bit;
+ break;
+ }
+ upa_writel(reg, p->reg);
+}
+
+static void fhc_left_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val)
+{
+ __fhc_set(led_cdev, led_val, FHC_CONTROL_LLED);
+}
+
+static void fhc_middle_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val)
+{
+ __fhc_set(led_cdev, led_val, FHC_CONTROL_MLED);
+}
+
+static void fhc_right_set(struct led_classdev *led_cdev,
+ enum led_brightness led_val)
+{
+ __fhc_set(led_cdev, led_val, FHC_CONTROL_RLED);
+}
+
+typedef void (*set_handler)(struct led_classdev *, enum led_brightness);
+struct led_type {
+ const char *name;
+ set_handler handler;
+ const char *default_trigger;
+};
+
+#define NUM_LEDS_PER_BOARD 3
+struct sunfire_drvdata {
+ struct sunfire_led leds[NUM_LEDS_PER_BOARD];
+};
+
+static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
+ struct led_type *types)
+{
+ struct sunfire_drvdata *p;
+ int i, err = -EINVAL;
+
+ if (pdev->num_resources != 1) {
+ printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n",
+ pdev->num_resources);
+ goto out;
+ }
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n");
+ goto out;
+ }
+
+ for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
+ struct led_classdev *lp = &p->leds[i].led_cdev;
+
+ p->leds[i].reg = (void __iomem *) pdev->resource[0].start;
+ lp->name = types[i].name;
+ lp->brightness = LED_FULL;
+ lp->brightness_set = types[i].handler;
+ lp->default_trigger = types[i].default_trigger;
+
+ err = led_classdev_register(&pdev->dev, lp);
+ if (err) {
+ printk(KERN_ERR PFX "Could not register %s LED\n",
+ lp->name);
+ goto out_unregister_led_cdevs;
+ }
+ }
+
+ dev_set_drvdata(&pdev->dev, p);
+
+ err = 0;
+out:
+ return err;
+
+out_unregister_led_cdevs:
+ for (i--; i >= 0; i--)
+ led_classdev_unregister(&p->leds[i].led_cdev);
+ goto out;
+}
+
+static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
+{
+ struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
+ int i;
+
+ for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
+ led_classdev_unregister(&p->leds[i].led_cdev);
+
+ kfree(p);
+
+ return 0;
+}
+
+static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = {
+ {
+ .name = "clockboard-left",
+ .handler = clockboard_left_set,
+ },
+ {
+ .name = "clockboard-middle",
+ .handler = clockboard_middle_set,
+ },
+ {
+ .name = "clockboard-right",
+ .handler = clockboard_right_set,
+ .default_trigger= "heartbeat",
+ },
+};
+
+static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev)
+{
+ return sunfire_led_generic_probe(pdev, clockboard_led_types);
+}
+
+static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
+ {
+ .name = "fhc-left",
+ .handler = fhc_left_set,
+ },
+ {
+ .name = "fhc-middle",
+ .handler = fhc_middle_set,
+ },
+ {
+ .name = "fhc-right",
+ .handler = fhc_right_set,
+ .default_trigger= "heartbeat",
+ },
+};
+
+static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev)
+{
+ return sunfire_led_generic_probe(pdev, fhc_led_types);
+}
+
+MODULE_ALIAS("platform:sunfire-clockboard-leds");
+MODULE_ALIAS("platform:sunfire-fhc-leds");
+
+static struct platform_driver sunfire_clockboard_led_driver = {
+ .probe = sunfire_clockboard_led_probe,
+ .remove = __devexit_p(sunfire_led_generic_remove),
+ .driver = {
+ .name = "sunfire-clockboard-leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct platform_driver sunfire_fhc_led_driver = {
+ .probe = sunfire_fhc_led_probe,
+ .remove = __devexit_p(sunfire_led_generic_remove),
+ .driver = {
+ .name = "sunfire-fhc-leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sunfire_leds_init(void)
+{
+ int err = platform_driver_register(&sunfire_clockboard_led_driver);
+
+ if (err) {
+ printk(KERN_ERR PFX "Could not register clock board LED driver\n");
+ return err;
+ }
+
+ err = platform_driver_register(&sunfire_fhc_led_driver);
+ if (err) {
+ printk(KERN_ERR PFX "Could not register FHC LED driver\n");
+ platform_driver_unregister(&sunfire_clockboard_led_driver);
+ }
+
+ return err;
+}
+
+static void __exit sunfire_leds_exit(void)
+{
+ platform_driver_unregister(&sunfire_clockboard_led_driver);
+ platform_driver_unregister(&sunfire_fhc_led_driver);
+}
+
+module_init(sunfire_leds_init);
+module_exit(sunfire_leds_exit);
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index e9994c81df6..fc9497bdd32 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -2096,15 +2096,8 @@ static int cafe_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret;
- u16 classword;
struct cafe_camera *cam;
- /*
- * Make sure we have a camera here - we'll get calls for
- * the other cafe devices as well.
- */
- pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
- if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
- return -ENODEV;
+
/*
* Start putting together one of our big camera structures.
*/
@@ -2292,8 +2285,8 @@ static int cafe_pci_resume(struct pci_dev *pdev)
static struct pci_device_id cafe_ids[] = {
- { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
- { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
+ PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
{ 0, }
};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c0b41e8bcd9..f2eeb38efa6 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -3,13 +3,14 @@
#
menuconfig MMC
- tristate "MMC/SD card support"
+ tristate "MMC/SD/SDIO card support"
depends on HAS_IOMEM
help
- MMC is the "multi-media card" bus protocol.
+ This selects MultiMediaCard, Secure Digital and Secure
+ Digital I/O support.
- If you want MMC support, you should say Y here and also
- to the specific driver for your MMC interface.
+ If you want MMC/SD/SDIO support, you should say Y here and
+ also to your specific host controller driver.
config MMC_DEBUG
bool "MMC debugging"
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index dd0f398ee2f..3f2a912659a 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -2,7 +2,7 @@
# MMC/SD card drivers
#
-comment "MMC/SD Card Drivers"
+comment "MMC/SD/SDIO Card Drivers"
config MMC_BLOCK
tristate "MMC block device driver"
@@ -34,7 +34,6 @@ config MMC_BLOCK_BOUNCE
config SDIO_UART
tristate "SDIO UART/GPS class support"
- depends on MMC
help
SDIO function driver for SDIO cards that implements the UART
class, as well as the GPS class which appears like a UART.
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index efacee0404a..24c97d3d16b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -58,7 +58,6 @@ struct mmc_blk_data {
struct mmc_queue queue;
unsigned int usage;
- unsigned int block_bits;
unsigned int read_only;
};
@@ -216,8 +215,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request brq;
- int ret = 1, data_size, i;
- struct scatterlist *sg;
+ int ret = 1;
mmc_claim_host(card->host);
@@ -233,13 +231,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq.data.blksz = 1 << md->block_bits;
+ brq.data.blksz = 512;
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
- if (brq.data.blocks > card->host->max_blk_count)
- brq.data.blocks = card->host->max_blk_count;
+ brq.data.blocks = req->nr_sectors;
if (brq.data.blocks > 1) {
/* SPI multiblock writes terminate using a special
@@ -271,24 +267,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
mmc_queue_bounce_pre(mq);
- /*
- * Adjust the sg list so it is the same size as the
- * request.
- */
- if (brq.data.blocks !=
- (req->nr_sectors >> (md->block_bits - 9))) {
- data_size = brq.data.blocks * brq.data.blksz;
- for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
- data_size -= sg->length;
- if (data_size <= 0) {
- sg->length += data_size;
- i++;
- break;
- }
- }
- brq.data.sg_len = i;
- }
-
mmc_wait_for_req(card->host, &brq.mrq);
mmc_queue_bounce_post(mq);
@@ -373,16 +351,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (rq_data_dir(req) != READ) {
if (mmc_card_sd(card)) {
u32 blocks;
- unsigned int bytes;
blocks = mmc_sd_num_wr_blocks(card);
if (blocks != (u32)-1) {
- if (card->csd.write_partial)
- bytes = blocks << md->block_bits;
- else
- bytes = blocks << 9;
spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, bytes);
+ ret = __blk_end_request(req, 0, blocks << 9);
spin_unlock_irq(&md->lock);
}
} else {
@@ -432,13 +405,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
*/
md->read_only = mmc_blk_readonly(card);
- /*
- * Both SD and MMC specifications state (although a bit
- * unclearly in the MMC case) that a block size of 512
- * bytes must always be supported by the card.
- */
- md->block_bits = 9;
-
md->disk = alloc_disk(1 << MMC_SHIFT);
if (md->disk == NULL) {
ret = -ENOMEM;
@@ -476,7 +442,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
- blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+ blk_queue_hardsect_size(md->queue.queue, 512);
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
@@ -514,7 +480,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = 1 << md->block_bits;
+ cmd.arg = 512;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_release_host(card->host);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 3dee97e7d16..406989e992b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -31,7 +31,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
/*
* We only like normal block requests.
*/
- if (!blk_fs_request(req) && !blk_pc_request(req)) {
+ if (!blk_fs_request(req)) {
blk_dump_rq_flags(req, "MMC bad request");
return BLKPREP_KILL;
}
@@ -131,6 +131,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
mq->req = NULL;
blk_queue_prep_rq(mq->queue, mmc_prep_request);
+ blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_hw_segs == 1) {
@@ -142,12 +143,19 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
bouncesz = host->max_req_size;
if (bouncesz > host->max_seg_size)
bouncesz = host->max_seg_size;
+ if (bouncesz > (host->max_blk_count * 512))
+ bouncesz = host->max_blk_count * 512;
+
+ if (bouncesz > 512) {
+ mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+ if (!mq->bounce_buf) {
+ printk(KERN_WARNING "%s: unable to "
+ "allocate bounce buffer\n",
+ mmc_card_name(card));
+ }
+ }
- mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
- if (!mq->bounce_buf) {
- printk(KERN_WARNING "%s: unable to allocate "
- "bounce buffer\n", mmc_card_name(card));
- } else {
+ if (mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
blk_queue_max_sectors(mq->queue, bouncesz / 512);
blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
@@ -175,7 +183,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
if (!mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
+ blk_queue_max_sectors(mq->queue,
+ min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 64b05c6270f..9c50e6f1c23 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -248,8 +248,12 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
sg_init_one(&sg, data_buf, len);
- if (card)
- mmc_set_data_timeout(&data, card);
+ /*
+ * The spec states that CSR and CID accesses have a timeout
+ * of 64 clock cycles.
+ */
+ data.timeout_ns = 0;
+ data.timeout_clks = 64;
mmc_wait_for_req(host, &mrq);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4eab79e09cc..fb99ccff908 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -165,6 +165,36 @@ static int sdio_enable_wide(struct mmc_card *card)
}
/*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int sdio_enable_hs(struct mmc_card *card)
+{
+ int ret;
+ u8 speed;
+
+ if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+ return 0;
+
+ if (!card->cccr.high_speed)
+ return 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+ if (ret)
+ return ret;
+
+ speed |= SDIO_SPEED_EHS;
+
+ ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+ if (ret)
+ return ret;
+
+ mmc_card_set_highspeed(card);
+ mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+
+ return 0;
+}
+
+/*
* Host is being removed. Free up the current card.
*/
static void mmc_sdio_remove(struct mmc_host *host)
@@ -333,10 +363,26 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
goto remove;
/*
- * No support for high-speed yet, so just set
- * the card's maximum speed.
+ * Switch to high-speed (if supported).
*/
- mmc_set_clock(host, card->cis.max_dtr);
+ err = sdio_enable_hs(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Change to the card's maximum speed.
+ */
+ if (mmc_card_highspeed(card)) {
+ /*
+ * The SDIO specification doesn't mention how
+ * the CIS transfer speed register relates to
+ * high-speed, but it seems that 50 MHz is
+ * mandatory.
+ */
+ mmc_set_clock(host, 50000000);
+ } else {
+ mmc_set_clock(host, card->cis.max_dtr);
+ }
/*
* Switch to wider bus (if supported).
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index c292e124107..bb192f90e8e 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -5,6 +5,8 @@
* Created: June 18, 2007
* Copyright: MontaVista Software Inc.
*
+ * Copyright 2008 Pierre Ossman
+ *
* 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
@@ -107,11 +109,14 @@ static int sdio_irq_thread(void *_host)
/*
* Give other threads a chance to run in the presence of
- * errors. FIXME: determine if due to card removal and
- * possibly exit this thread if so.
+ * errors.
*/
- if (ret < 0)
- ssleep(1);
+ if (ret < 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!kthread_should_stop())
+ schedule_timeout(HZ);
+ set_current_state(TASK_RUNNING);
+ }
/*
* Adaptive polling frequency based on the assumption
@@ -154,7 +159,8 @@ static int sdio_card_irq_get(struct mmc_card *card)
if (!host->sdio_irqs++) {
atomic_set(&host->sdio_irq_thread_abort, 0);
host->sdio_irq_thread =
- kthread_run(sdio_irq_thread, host, "ksdiorqd");
+ kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
+ mmc_hostname(host));
if (IS_ERR(host->sdio_irq_thread)) {
int err = PTR_ERR(host->sdio_irq_thread);
host->sdio_irqs--;
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ea8d7a3490d..dfa585f7fea 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -2,7 +2,7 @@
# MMC/SD host controller drivers
#
-comment "MMC/SD Host Controller Drivers"
+comment "MMC/SD/SDIO Host Controller Drivers"
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
@@ -114,6 +114,17 @@ config MMC_ATMELMCI
If unsure, say N.
+config MMC_ATMELMCI_DMA
+ bool "Atmel MCI DMA support (EXPERIMENTAL)"
+ depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
+ help
+ Say Y here to have the Atmel MCI driver use a DMA engine to
+ do data transfers and thus increase the throughput and
+ reduce the CPU utilization. Note that this is highly
+ experimental and may cause the driver to lock up.
+
+ If unsure, say N.
+
config MMC_IMX
tristate "Motorola i.MX Multimedia Card Interface support"
depends on ARCH_IMX
@@ -141,21 +152,22 @@ config MMC_TIFM_SD
module will be called tifm_sd.
config MMC_SPI
- tristate "MMC/SD over SPI"
- depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA
+ tristate "MMC/SD/SDIO over SPI"
+ depends on SPI_MASTER && !HIGHMEM && HAS_DMA
select CRC7
select CRC_ITU_T
help
- Some systems accss MMC/SD cards using a SPI controller instead of
- using a "native" MMC/SD controller. This has a disadvantage of
- being relatively high overhead, but a compensating advantage of
- working on many systems without dedicated MMC/SD controllers.
+ Some systems accss MMC/SD/SDIO cards using a SPI controller
+ instead of using a "native" MMC/SD/SDIO controller. This has a
+ disadvantage of being relatively high overhead, but a compensating
+ advantage of working on many systems without dedicated MMC/SD/SDIO
+ controllers.
If unsure, or if your system has no SPI master driver, say N.
config MMC_S3C
tristate "Samsung S3C SD/MMC Card Interface support"
- depends on ARCH_S3C2410 && MMC
+ depends on ARCH_S3C2410
help
This selects a driver for the MCI interface found in
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@@ -166,7 +178,7 @@ config MMC_S3C
config MMC_SDRICOH_CS
tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
- depends on EXPERIMENTAL && MMC && PCI && PCMCIA
+ depends on EXPERIMENTAL && PCI && PCMCIA
help
Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
card whenever you insert a MMC or SD card into the card slot.
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
index 26bd80e6503..b58364ed6bb 100644
--- a/drivers/mmc/host/atmel-mci-regs.h
+++ b/drivers/mmc/host/atmel-mci-regs.h
@@ -25,8 +25,10 @@
#define MCI_SDCR 0x000c /* SD Card / SDIO */
# define MCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */
# define MCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */
-# define MCI_SDCBUS_1BIT ( 0 << 7) /* 1-bit data bus */
-# define MCI_SDCBUS_4BIT ( 1 << 7) /* 4-bit data bus */
+# define MCI_SDCSEL_MASK ( 3 << 0)
+# define MCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */
+# define MCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */
+# define MCI_SDCBUS_MASK ( 3 << 6)
#define MCI_ARGR 0x0010 /* Command Argument */
#define MCI_CMDR 0x0014 /* Command */
# define MCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 00008967ef7..7a3f2436b01 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -11,6 +11,8 @@
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
@@ -33,64 +35,178 @@
#include "atmel-mci-regs.h"
#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
+#define ATMCI_DMA_THRESHOLD 16
enum {
EVENT_CMD_COMPLETE = 0,
- EVENT_DATA_ERROR,
- EVENT_DATA_COMPLETE,
- EVENT_STOP_SENT,
- EVENT_STOP_COMPLETE,
EVENT_XFER_COMPLETE,
+ EVENT_DATA_COMPLETE,
+ EVENT_DATA_ERROR,
+};
+
+enum atmel_mci_state {
+ STATE_IDLE = 0,
+ STATE_SENDING_CMD,
+ STATE_SENDING_DATA,
+ STATE_DATA_BUSY,
+ STATE_SENDING_STOP,
+ STATE_DATA_ERROR,
+};
+
+struct atmel_mci_dma {
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ struct dma_client client;
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *data_desc;
+#endif
};
+/**
+ * struct atmel_mci - MMC controller state shared between all slots
+ * @lock: Spinlock protecting the queue and associated data.
+ * @regs: Pointer to MMIO registers.
+ * @sg: Scatterlist entry currently being processed by PIO code, if any.
+ * @pio_offset: Offset into the current scatterlist entry.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ * or NULL if the controller is idle.
+ * @cmd: The command currently being sent to the card, or NULL.
+ * @data: The data currently being transferred, or NULL if no data
+ * transfer is in progress.
+ * @dma: DMA client state.
+ * @data_chan: DMA channel being used for the current data transfer.
+ * @cmd_status: Snapshot of SR taken upon completion of the current
+ * command. Only valid when EVENT_CMD_COMPLETE is pending.
+ * @data_status: Snapshot of SR taken upon completion of the current
+ * data transfer. Only valid when EVENT_DATA_COMPLETE or
+ * EVENT_DATA_ERROR is pending.
+ * @stop_cmdr: Value to be loaded into CMDR when the stop command is
+ * to be sent.
+ * @tasklet: Tasklet running the request state machine.
+ * @pending_events: Bitmask of events flagged by the interrupt handler
+ * to be processed by the tasklet.
+ * @completed_events: Bitmask of events which the state machine has
+ * processed.
+ * @state: Tasklet state.
+ * @queue: List of slots waiting for access to the controller.
+ * @need_clock_update: Update the clock rate before the next request.
+ * @need_reset: Reset controller before next request.
+ * @mode_reg: Value of the MR register.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+ * rate and timeout calculations.
+ * @mapbase: Physical address of the MMIO registers.
+ * @mck: The peripheral bus clock hooked up to the MMC controller.
+ * @pdev: Platform device associated with the MMC controller.
+ * @slot: Slots sharing this MMC controller.
+ *
+ * Locking
+ * =======
+ *
+ * @lock is a softirq-safe spinlock protecting @queue as well as
+ * @cur_slot, @mrq and @state. These must always be updated
+ * at the same time while holding @lock.
+ *
+ * @lock also protects mode_reg and need_clock_update since these are
+ * used to synchronize mode register updates with the queue
+ * processing.
+ *
+ * The @mrq field of struct atmel_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
+ *
+ * @pending_events and @completed_events are accessed using atomic bit
+ * operations, so they don't need any locking.
+ *
+ * None of the fields touched by the interrupt handler need any
+ * locking. However, ordering is important: Before EVENT_DATA_ERROR or
+ * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
+ * interrupts must be disabled and @data_status updated with a
+ * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
+ * CMDRDY interupt must be disabled and @cmd_status updated with a
+ * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
+ * bytes_xfered field of @data must be written. This is ensured by
+ * using barriers.
+ */
struct atmel_mci {
- struct mmc_host *mmc;
+ spinlock_t lock;
void __iomem *regs;
struct scatterlist *sg;
unsigned int pio_offset;
+ struct atmel_mci_slot *cur_slot;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
+ struct atmel_mci_dma dma;
+ struct dma_chan *data_chan;
+
u32 cmd_status;
u32 data_status;
- u32 stop_status;
u32 stop_cmdr;
- u32 mode_reg;
- u32 sdc_reg;
-
struct tasklet_struct tasklet;
unsigned long pending_events;
unsigned long completed_events;
+ enum atmel_mci_state state;
+ struct list_head queue;
- int present;
- int detect_pin;
- int wp_pin;
-
- /* For detect pin debouncing */
- struct timer_list detect_timer;
-
+ bool need_clock_update;
+ bool need_reset;
+ u32 mode_reg;
unsigned long bus_hz;
unsigned long mapbase;
struct clk *mck;
struct platform_device *pdev;
+
+ struct atmel_mci_slot *slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
+/**
+ * struct atmel_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @sdc_reg: Value of SDCR to be written before using this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ * processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ * &struct atmel_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @flags: Random state bits associated with the slot.
+ * @detect_pin: GPIO pin used for card detection, or negative if not
+ * available.
+ * @wp_pin: GPIO pin used for card write protect sending, or negative
+ * if not available.
+ * @detect_timer: Timer used for debouncing @detect_pin interrupts.
+ */
+struct atmel_mci_slot {
+ struct mmc_host *mmc;
+ struct atmel_mci *host;
+
+ u32 sdc_reg;
+
+ struct mmc_request *mrq;
+ struct list_head queue_node;
+
+ unsigned int clock;
+ unsigned long flags;
+#define ATMCI_CARD_PRESENT 0
+#define ATMCI_CARD_NEED_INIT 1
+#define ATMCI_SHUTDOWN 2
+
+ int detect_pin;
+ int wp_pin;
+
+ struct timer_list detect_timer;
};
-#define atmci_is_completed(host, event) \
- test_bit(event, &host->completed_events)
#define atmci_test_and_clear_pending(host, event) \
test_and_clear_bit(event, &host->pending_events)
-#define atmci_test_and_set_completed(host, event) \
- test_and_set_bit(event, &host->completed_events)
#define atmci_set_completed(host, event) \
set_bit(event, &host->completed_events)
#define atmci_set_pending(host, event) \
set_bit(event, &host->pending_events)
-#define atmci_clear_pending(host, event) \
- clear_bit(event, &host->pending_events)
/*
* The debugfs stuff below is mostly optimized away when
@@ -98,14 +214,15 @@ struct atmel_mci {
*/
static int atmci_req_show(struct seq_file *s, void *v)
{
- struct atmel_mci *host = s->private;
- struct mmc_request *mrq = host->mrq;
+ struct atmel_mci_slot *slot = s->private;
+ struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_command *stop;
struct mmc_data *data;
/* Make sure we get a consistent snapshot */
- spin_lock_irq(&host->mmc->lock);
+ spin_lock_bh(&slot->host->lock);
+ mrq = slot->mrq;
if (mrq) {
cmd = mrq->cmd;
@@ -130,7 +247,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
stop->resp[2], stop->error);
}
- spin_unlock_irq(&host->mmc->lock);
+ spin_unlock_bh(&slot->host->lock);
return 0;
}
@@ -193,12 +310,16 @@ static int atmci_regs_show(struct seq_file *s, void *v)
if (!buf)
return -ENOMEM;
- /* Grab a more or less consistent snapshot */
- spin_lock_irq(&host->mmc->lock);
+ /*
+ * Grab a more or less consistent snapshot. Note that we're
+ * not disabling interrupts, so IMR and SR may not be
+ * consistent.
+ */
+ spin_lock_bh(&host->lock);
clk_enable(host->mck);
memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
clk_disable(host->mck);
- spin_unlock_irq(&host->mmc->lock);
+ spin_unlock_bh(&host->lock);
seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
buf[MCI_MR / 4],
@@ -236,13 +357,13 @@ static const struct file_operations atmci_regs_fops = {
.release = single_release,
};
-static void atmci_init_debugfs(struct atmel_mci *host)
+static void atmci_init_debugfs(struct atmel_mci_slot *slot)
{
- struct mmc_host *mmc;
- struct dentry *root;
- struct dentry *node;
+ struct mmc_host *mmc = slot->mmc;
+ struct atmel_mci *host = slot->host;
+ struct dentry *root;
+ struct dentry *node;
- mmc = host->mmc;
root = mmc->debugfs_root;
if (!root)
return;
@@ -254,7 +375,11 @@ static void atmci_init_debugfs(struct atmel_mci *host)
if (!node)
goto err;
- node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
+ node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+ if (!node)
+ goto err;
+
+ node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
if (!node)
goto err;
@@ -271,25 +396,7 @@ static void atmci_init_debugfs(struct atmel_mci *host)
return;
err:
- dev_err(&host->pdev->dev,
- "failed to initialize debugfs for controller\n");
-}
-
-static void atmci_enable(struct atmel_mci *host)
-{
- clk_enable(host->mck);
- mci_writel(host, CR, MCI_CR_MCIEN);
- mci_writel(host, MR, host->mode_reg);
- mci_writel(host, SDCR, host->sdc_reg);
-}
-
-static void atmci_disable(struct atmel_mci *host)
-{
- mci_writel(host, CR, MCI_CR_SWRST);
-
- /* Stall until write is complete, then disable the bus clock */
- mci_readl(host, SR);
- clk_disable(host->mck);
+ dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
}
static inline unsigned int ns_to_clocks(struct atmel_mci *host,
@@ -299,7 +406,7 @@ static inline unsigned int ns_to_clocks(struct atmel_mci *host,
}
static void atmci_set_timeout(struct atmel_mci *host,
- struct mmc_data *data)
+ struct atmel_mci_slot *slot, struct mmc_data *data)
{
static unsigned dtomul_to_shift[] = {
0, 4, 7, 8, 10, 12, 16, 20
@@ -322,7 +429,7 @@ static void atmci_set_timeout(struct atmel_mci *host,
dtocyc = 15;
}
- dev_vdbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
+ dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
dtocyc << dtomul_to_shift[dtomul]);
mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc)));
}
@@ -375,15 +482,12 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
}
static void atmci_start_command(struct atmel_mci *host,
- struct mmc_command *cmd,
- u32 cmd_flags)
+ struct mmc_command *cmd, u32 cmd_flags)
{
- /* Must read host->cmd after testing event flags */
- smp_rmb();
WARN_ON(host->cmd);
host->cmd = cmd;
- dev_vdbg(&host->mmc->class_dev,
+ dev_vdbg(&host->pdev->dev,
"start command: ARGR=0x%08x CMDR=0x%08x\n",
cmd->arg, cmd_flags);
@@ -391,34 +495,157 @@ static void atmci_start_command(struct atmel_mci *host,
mci_writel(host, CMDR, cmd_flags);
}
-static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data)
+static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
{
- struct atmel_mci *host = mmc_priv(mmc);
-
atmci_start_command(host, data->stop, host->stop_cmdr);
mci_writel(host, IER, MCI_CMDRDY);
}
-static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+static void atmci_dma_cleanup(struct atmel_mci *host)
{
- struct atmel_mci *host = mmc_priv(mmc);
+ struct mmc_data *data = host->data;
- WARN_ON(host->cmd || host->data);
- host->mrq = NULL;
+ dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+ ((data->flags & MMC_DATA_WRITE)
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+}
+
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+ struct dma_chan *chan = host->data_chan;
+
+ if (chan) {
+ chan->device->device_terminate_all(chan);
+ atmci_dma_cleanup(host);
+ } else {
+ /* Data transfer was stopped by the interrupt handler */
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ mci_writel(host, IER, MCI_NOTBUSY);
+ }
+}
+
+/* This function is called by the DMA driver from tasklet context. */
+static void atmci_dma_complete(void *arg)
+{
+ struct atmel_mci *host = arg;
+ struct mmc_data *data = host->data;
+
+ dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+ atmci_dma_cleanup(host);
+
+ /*
+ * If the card was removed, data will be NULL. No point trying
+ * to send the stop command or waiting for NBUSY in this case.
+ */
+ if (data) {
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+
+ /*
+ * Regardless of what the documentation says, we have
+ * to wait for NOTBUSY even after block read
+ * operations.
+ *
+ * When the DMA transfer is complete, the controller
+ * may still be reading the CRC from the card, i.e.
+ * the data transfer is still in progress and we
+ * haven't seen all the potential error bits yet.
+ *
+ * The interrupt handler will schedule a different
+ * tasklet to finish things up when the data transfer
+ * is completely done.
+ *
+ * We may not complete the mmc request here anyway
+ * because the mmc layer may call back and cause us to
+ * violate the "don't submit new operations from the
+ * completion callback" rule of the dma engine
+ * framework.
+ */
+ mci_writel(host, IER, MCI_NOTBUSY);
+ }
+}
+
+static int
+atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sg;
+ unsigned int i;
+ enum dma_data_direction direction;
+
+ /*
+ * We don't do DMA on "complex" transfers, i.e. with
+ * non-word-aligned buffers or lengths. Also, we don't bother
+ * with all the DMA setup overhead for short transfers.
+ */
+ if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
+ return -EINVAL;
+ if (data->blksz & 3)
+ return -EINVAL;
+
+ for_each_sg(data->sg, sg, data->sg_len, i) {
+ if (sg->offset & 3 || sg->length & 3)
+ return -EINVAL;
+ }
+
+ /* If we don't have a channel, we can't do DMA */
+ chan = host->dma.chan;
+ if (chan) {
+ dma_chan_get(chan);
+ host->data_chan = chan;
+ }
+
+ if (!chan)
+ return -ENODEV;
+
+ if (data->flags & MMC_DATA_READ)
+ direction = DMA_FROM_DEVICE;
+ else
+ direction = DMA_TO_DEVICE;
+
+ desc = chan->device->device_prep_slave_sg(chan,
+ data->sg, data->sg_len, direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc)
+ return -ENOMEM;
- atmci_disable(host);
+ host->dma.data_desc = desc;
+ desc->callback = atmci_dma_complete;
+ desc->callback_param = host;
+ desc->tx_submit(desc);
- mmc_request_done(mmc, mrq);
+ /* Go! */
+ chan->device->device_issue_pending(chan);
+
+ return 0;
+}
+
+#else /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+ return -ENOSYS;
}
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+ /* Data transfer was stopped by the interrupt handler */
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ mci_writel(host, IER, MCI_NOTBUSY);
+}
+
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
/*
* Returns a mask of interrupt flags to be enabled after the whole
* request has been prepared.
*/
-static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
+static u32 atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
{
- struct atmel_mci *host = mmc_priv(mmc);
- u32 iflags;
+ u32 iflags;
data->error = -EINPROGRESS;
@@ -426,77 +653,89 @@ static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
host->sg = NULL;
host->data = data;
- dev_vdbg(&mmc->class_dev, "BLKR=0x%08x\n",
- MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
-
iflags = ATMCI_DATA_ERROR_FLAGS;
- host->sg = data->sg;
- host->pio_offset = 0;
- if (data->flags & MMC_DATA_READ)
- iflags |= MCI_RXRDY;
- else
- iflags |= MCI_TXRDY;
+ if (atmci_submit_data_dma(host, data)) {
+ host->data_chan = NULL;
+
+ /*
+ * Errata: MMC data write operation with less than 12
+ * bytes is impossible.
+ *
+ * Errata: MCI Transmit Data Register (TDR) FIFO
+ * corruption when length is not multiple of 4.
+ */
+ if (data->blocks * data->blksz < 12
+ || (data->blocks * data->blksz) & 3)
+ host->need_reset = true;
+
+ host->sg = data->sg;
+ host->pio_offset = 0;
+ if (data->flags & MMC_DATA_READ)
+ iflags |= MCI_RXRDY;
+ else
+ iflags |= MCI_TXRDY;
+ }
return iflags;
}
-static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+static void atmci_start_request(struct atmel_mci *host,
+ struct atmel_mci_slot *slot)
{
- struct atmel_mci *host = mmc_priv(mmc);
- struct mmc_data *data;
+ struct mmc_request *mrq;
struct mmc_command *cmd;
+ struct mmc_data *data;
u32 iflags;
- u32 cmdflags = 0;
-
- iflags = mci_readl(host, IMR);
- if (iflags)
- dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
- mci_readl(host, IMR));
-
- WARN_ON(host->mrq != NULL);
-
- /*
- * We may "know" the card is gone even though there's still an
- * electrical connection. If so, we really need to communicate
- * this to the MMC core since there won't be any more
- * interrupts as the card is completely removed. Otherwise,
- * the MMC core might believe the card is still there even
- * though the card was just removed very slowly.
- */
- if (!host->present) {
- mrq->cmd->error = -ENOMEDIUM;
- mmc_request_done(mmc, mrq);
- return;
- }
+ u32 cmdflags;
+ mrq = slot->mrq;
+ host->cur_slot = slot;
host->mrq = mrq;
+
host->pending_events = 0;
host->completed_events = 0;
+ host->data_status = 0;
- atmci_enable(host);
+ if (host->need_reset) {
+ mci_writel(host, CR, MCI_CR_SWRST);
+ mci_writel(host, CR, MCI_CR_MCIEN);
+ mci_writel(host, MR, host->mode_reg);
+ host->need_reset = false;
+ }
+ mci_writel(host, SDCR, slot->sdc_reg);
- /* We don't support multiple blocks of weird lengths. */
+ iflags = mci_readl(host, IMR);
+ if (iflags)
+ dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
+ iflags);
+
+ if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
+ /* Send init sequence (74 clock cycles) */
+ mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
+ while (!(mci_readl(host, SR) & MCI_CMDRDY))
+ cpu_relax();
+ }
data = mrq->data;
if (data) {
- if (data->blocks > 1 && data->blksz & 3)
- goto fail;
- atmci_set_timeout(host, data);
+ atmci_set_timeout(host, slot, data);
/* Must set block count/size before sending command */
mci_writel(host, BLKR, MCI_BCNT(data->blocks)
| MCI_BLKLEN(data->blksz));
+ dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
+ MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
}
iflags = MCI_CMDRDY;
cmd = mrq->cmd;
- cmdflags = atmci_prepare_command(mmc, cmd);
+ cmdflags = atmci_prepare_command(slot->mmc, cmd);
atmci_start_command(host, cmd, cmdflags);
if (data)
- iflags |= atmci_submit_data(mmc, data);
+ iflags |= atmci_submit_data(host, data);
if (mrq->stop) {
- host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
+ host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
host->stop_cmdr |= MCI_CMDR_STOP_XFER;
if (!(data->flags & MMC_DATA_WRITE))
host->stop_cmdr |= MCI_CMDR_TRDIR_READ;
@@ -513,59 +752,156 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
* prepared yet.)
*/
mci_writel(host, IER, iflags);
+}
- return;
+static void atmci_queue_request(struct atmel_mci *host,
+ struct atmel_mci_slot *slot, struct mmc_request *mrq)
+{
+ dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
+ host->state);
+
+ spin_lock_bh(&host->lock);
+ slot->mrq = mrq;
+ if (host->state == STATE_IDLE) {
+ host->state = STATE_SENDING_CMD;
+ atmci_start_request(host, slot);
+ } else {
+ list_add_tail(&slot->queue_node, &host->queue);
+ }
+ spin_unlock_bh(&host->lock);
+}
-fail:
- atmci_disable(host);
- host->mrq = NULL;
- mrq->cmd->error = -EINVAL;
- mmc_request_done(mmc, mrq);
+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
+ struct atmel_mci *host = slot->host;
+ struct mmc_data *data;
+
+ WARN_ON(slot->mrq);
+
+ /*
+ * We may "know" the card is gone even though there's still an
+ * electrical connection. If so, we really need to communicate
+ * this to the MMC core since there won't be any more
+ * interrupts as the card is completely removed. Otherwise,
+ * the MMC core might believe the card is still there even
+ * though the card was just removed very slowly.
+ */
+ if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
+ mrq->cmd->error = -ENOMEDIUM;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
+ /* We don't support multiple blocks of weird lengths. */
+ data = mrq->data;
+ if (data && data->blocks > 1 && data->blksz & 3) {
+ mrq->cmd->error = -EINVAL;
+ mmc_request_done(mmc, mrq);
+ }
+
+ atmci_queue_request(host, slot, mrq);
}
static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
+ struct atmel_mci *host = slot->host;
+ unsigned int i;
+
+ slot->sdc_reg &= ~MCI_SDCBUS_MASK;
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ slot->sdc_reg |= MCI_SDCBUS_1BIT;
+ break;
+ case MMC_BUS_WIDTH_4:
+ slot->sdc_reg = MCI_SDCBUS_4BIT;
+ break;
+ }
if (ios->clock) {
+ unsigned int clock_min = ~0U;
u32 clkdiv;
- /* Set clock rate */
- clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1;
+ spin_lock_bh(&host->lock);
+ if (!host->mode_reg) {
+ clk_enable(host->mck);
+ mci_writel(host, CR, MCI_CR_SWRST);
+ mci_writel(host, CR, MCI_CR_MCIEN);
+ }
+
+ /*
+ * Use mirror of ios->clock to prevent race with mmc
+ * core ios update when finding the minimum.
+ */
+ slot->clock = ios->clock;
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i] && host->slot[i]->clock
+ && host->slot[i]->clock < clock_min)
+ clock_min = host->slot[i]->clock;
+ }
+
+ /* Calculate clock divider */
+ clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
if (clkdiv > 255) {
dev_warn(&mmc->class_dev,
"clock %u too slow; using %lu\n",
- ios->clock, host->bus_hz / (2 * 256));
+ clock_min, host->bus_hz / (2 * 256));
clkdiv = 255;
}
+ /*
+ * WRPROOF and RDPROOF prevent overruns/underruns by
+ * stopping the clock when the FIFO is full/empty.
+ * This state is not expected to last for long.
+ */
host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
| MCI_MR_RDPROOF;
- }
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- host->sdc_reg = 0;
- break;
- case MMC_BUS_WIDTH_4:
- host->sdc_reg = MCI_SDCBUS_4BIT;
- break;
+ if (list_empty(&host->queue))
+ mci_writel(host, MR, host->mode_reg);
+ else
+ host->need_clock_update = true;
+
+ spin_unlock_bh(&host->lock);
+ } else {
+ bool any_slot_active = false;
+
+ spin_lock_bh(&host->lock);
+ slot->clock = 0;
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i] && host->slot[i]->clock) {
+ any_slot_active = true;
+ break;
+ }
+ }
+ if (!any_slot_active) {
+ mci_writel(host, CR, MCI_CR_MCIDIS);
+ if (host->mode_reg) {
+ mci_readl(host, MR);
+ clk_disable(host->mck);
+ }
+ host->mode_reg = 0;
+ }
+ spin_unlock_bh(&host->lock);
}
switch (ios->power_mode) {
- case MMC_POWER_ON:
- /* Send init sequence (74 clock cycles) */
- atmci_enable(host);
- mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
- while (!(mci_readl(host, SR) & MCI_CMDRDY))
- cpu_relax();
- atmci_disable(host);
+ case MMC_POWER_UP:
+ set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
break;
default:
/*
* TODO: None of the currently available AVR32-based
* boards allow MMC power to be turned off. Implement
* power control when this can be tested properly.
+ *
+ * We also need to hook this into the clock management
+ * somehow so that newly inserted cards aren't
+ * subjected to a fast clock before we have a chance
+ * to figure out what the maximum rate is. Currently,
+ * there's no way to avoid this, and there never will
+ * be for boards that don't support power control.
*/
break;
}
@@ -573,31 +909,82 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
static int atmci_get_ro(struct mmc_host *mmc)
{
- int read_only = 0;
- struct atmel_mci *host = mmc_priv(mmc);
+ int read_only = -ENOSYS;
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
- if (gpio_is_valid(host->wp_pin)) {
- read_only = gpio_get_value(host->wp_pin);
+ if (gpio_is_valid(slot->wp_pin)) {
+ read_only = gpio_get_value(slot->wp_pin);
dev_dbg(&mmc->class_dev, "card is %s\n",
read_only ? "read-only" : "read-write");
- } else {
- dev_dbg(&mmc->class_dev,
- "no pin for checking read-only switch."
- " Assuming write-enable.\n");
}
return read_only;
}
-static struct mmc_host_ops atmci_ops = {
+static int atmci_get_cd(struct mmc_host *mmc)
+{
+ int present = -ENOSYS;
+ struct atmel_mci_slot *slot = mmc_priv(mmc);
+
+ if (gpio_is_valid(slot->detect_pin)) {
+ present = !gpio_get_value(slot->detect_pin);
+ dev_dbg(&mmc->class_dev, "card is %spresent\n",
+ present ? "" : "not ");
+ }
+
+ return present;
+}
+
+static const struct mmc_host_ops atmci_ops = {
.request = atmci_request,
.set_ios = atmci_set_ios,
.get_ro = atmci_get_ro,
+ .get_cd = atmci_get_cd,
};
+/* Called with host->lock held */
+static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
+ __releases(&host->lock)
+ __acquires(&host->lock)
+{
+ struct atmel_mci_slot *slot = NULL;
+ struct mmc_host *prev_mmc = host->cur_slot->mmc;
+
+ WARN_ON(host->cmd || host->data);
+
+ /*
+ * Update the MMC clock rate if necessary. This may be
+ * necessary if set_ios() is called when a different slot is
+ * busy transfering data.
+ */
+ if (host->need_clock_update)
+ mci_writel(host, MR, host->mode_reg);
+
+ host->cur_slot->mrq = NULL;
+ host->mrq = NULL;
+ if (!list_empty(&host->queue)) {
+ slot = list_entry(host->queue.next,
+ struct atmel_mci_slot, queue_node);
+ list_del(&slot->queue_node);
+ dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+ mmc_hostname(slot->mmc));
+ host->state = STATE_SENDING_CMD;
+ atmci_start_request(host, slot);
+ } else {
+ dev_vdbg(&host->pdev->dev, "list empty\n");
+ host->state = STATE_IDLE;
+ }
+
+ spin_unlock(&host->lock);
+ mmc_request_done(prev_mmc, mrq);
+ spin_lock(&host->lock);
+}
+
static void atmci_command_complete(struct atmel_mci *host,
- struct mmc_command *cmd, u32 status)
+ struct mmc_command *cmd)
{
+ u32 status = host->cmd_status;
+
/* Read the response from the card (up to 16 bytes) */
cmd->resp[0] = mci_readl(host, RSPR);
cmd->resp[1] = mci_readl(host, RSPR);
@@ -614,11 +1001,12 @@ static void atmci_command_complete(struct atmel_mci *host,
cmd->error = 0;
if (cmd->error) {
- dev_dbg(&host->mmc->class_dev,
+ dev_dbg(&host->pdev->dev,
"command error: status=0x%08x\n", status);
if (cmd->data) {
host->data = NULL;
+ atmci_stop_dma(host);
mci_writel(host, IDR, MCI_NOTBUSY
| MCI_TXRDY | MCI_RXRDY
| ATMCI_DATA_ERROR_FLAGS);
@@ -628,146 +1016,222 @@ static void atmci_command_complete(struct atmel_mci *host,
static void atmci_detect_change(unsigned long data)
{
- struct atmel_mci *host = (struct atmel_mci *)data;
- struct mmc_request *mrq = host->mrq;
- int present;
+ struct atmel_mci_slot *slot = (struct atmel_mci_slot *)data;
+ bool present;
+ bool present_old;
/*
- * atmci_remove() sets detect_pin to -1 before freeing the
- * interrupt. We must not re-enable the interrupt if it has
- * been freed.
+ * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
+ * freeing the interrupt. We must not re-enable the interrupt
+ * if it has been freed, and if we're shutting down, it
+ * doesn't really matter whether the card is present or not.
*/
smp_rmb();
- if (!gpio_is_valid(host->detect_pin))
+ if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
return;
- enable_irq(gpio_to_irq(host->detect_pin));
- present = !gpio_get_value(host->detect_pin);
+ enable_irq(gpio_to_irq(slot->detect_pin));
+ present = !gpio_get_value(slot->detect_pin);
+ present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
+
+ dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
+ present, present_old);
- dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
- present, host->present);
+ if (present != present_old) {
+ struct atmel_mci *host = slot->host;
+ struct mmc_request *mrq;
- if (present != host->present) {
- dev_dbg(&host->mmc->class_dev, "card %s\n",
+ dev_dbg(&slot->mmc->class_dev, "card %s\n",
present ? "inserted" : "removed");
- host->present = present;
- /* Reset controller if card is gone */
- if (!present) {
- mci_writel(host, CR, MCI_CR_SWRST);
- mci_writel(host, IDR, ~0UL);
- mci_writel(host, CR, MCI_CR_MCIEN);
- }
+ spin_lock(&host->lock);
+
+ if (!present)
+ clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+ else
+ set_bit(ATMCI_CARD_PRESENT, &slot->flags);
/* Clean up queue if present */
+ mrq = slot->mrq;
if (mrq) {
- /*
- * Reset controller to terminate any ongoing
- * commands or data transfers.
- */
- mci_writel(host, CR, MCI_CR_SWRST);
+ if (mrq == host->mrq) {
+ /*
+ * Reset controller to terminate any ongoing
+ * commands or data transfers.
+ */
+ mci_writel(host, CR, MCI_CR_SWRST);
+ mci_writel(host, CR, MCI_CR_MCIEN);
+ mci_writel(host, MR, host->mode_reg);
- if (!atmci_is_completed(host, EVENT_CMD_COMPLETE))
- mrq->cmd->error = -ENOMEDIUM;
-
- if (mrq->data && !atmci_is_completed(host,
- EVENT_DATA_COMPLETE)) {
host->data = NULL;
- mrq->data->error = -ENOMEDIUM;
+ host->cmd = NULL;
+
+ switch (host->state) {
+ case STATE_IDLE:
+ break;
+ case STATE_SENDING_CMD:
+ mrq->cmd->error = -ENOMEDIUM;
+ if (!mrq->data)
+ break;
+ /* fall through */
+ case STATE_SENDING_DATA:
+ mrq->data->error = -ENOMEDIUM;
+ atmci_stop_dma(host);
+ break;
+ case STATE_DATA_BUSY:
+ case STATE_DATA_ERROR:
+ if (mrq->data->error == -EINPROGRESS)
+ mrq->data->error = -ENOMEDIUM;
+ if (!mrq->stop)
+ break;
+ /* fall through */
+ case STATE_SENDING_STOP:
+ mrq->stop->error = -ENOMEDIUM;
+ break;
+ }
+
+ atmci_request_end(host, mrq);
+ } else {
+ list_del(&slot->queue_node);
+ mrq->cmd->error = -ENOMEDIUM;
+ if (mrq->data)
+ mrq->data->error = -ENOMEDIUM;
+ if (mrq->stop)
+ mrq->stop->error = -ENOMEDIUM;
+
+ spin_unlock(&host->lock);
+ mmc_request_done(slot->mmc, mrq);
+ spin_lock(&host->lock);
}
- if (mrq->stop && !atmci_is_completed(host,
- EVENT_STOP_COMPLETE))
- mrq->stop->error = -ENOMEDIUM;
-
- host->cmd = NULL;
- atmci_request_end(host->mmc, mrq);
}
+ spin_unlock(&host->lock);
- mmc_detect_change(host->mmc, 0);
+ mmc_detect_change(slot->mmc, 0);
}
}
static void atmci_tasklet_func(unsigned long priv)
{
- struct mmc_host *mmc = (struct mmc_host *)priv;
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci *host = (struct atmel_mci *)priv;
struct mmc_request *mrq = host->mrq;
struct mmc_data *data = host->data;
+ struct mmc_command *cmd = host->cmd;
+ enum atmel_mci_state state = host->state;
+ enum atmel_mci_state prev_state;
+ u32 status;
+
+ spin_lock(&host->lock);
- dev_vdbg(&mmc->class_dev,
- "tasklet: pending/completed/mask %lx/%lx/%x\n",
- host->pending_events, host->completed_events,
+ state = host->state;
+
+ dev_vdbg(&host->pdev->dev,
+ "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
+ state, host->pending_events, host->completed_events,
mci_readl(host, IMR));
- if (atmci_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) {
- /*
- * host->cmd must be set to NULL before the interrupt
- * handler sees EVENT_CMD_COMPLETE
- */
- host->cmd = NULL;
- smp_wmb();
- atmci_set_completed(host, EVENT_CMD_COMPLETE);
- atmci_command_complete(host, mrq->cmd, host->cmd_status);
-
- if (!mrq->cmd->error && mrq->stop
- && atmci_is_completed(host, EVENT_XFER_COMPLETE)
- && !atmci_test_and_set_completed(host,
- EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, mrq->data);
- }
- if (atmci_test_and_clear_pending(host, EVENT_STOP_COMPLETE)) {
- /*
- * host->cmd must be set to NULL before the interrupt
- * handler sees EVENT_STOP_COMPLETE
- */
- host->cmd = NULL;
- smp_wmb();
- atmci_set_completed(host, EVENT_STOP_COMPLETE);
- atmci_command_complete(host, mrq->stop, host->stop_status);
- }
- if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) {
- u32 status = host->data_status;
+ do {
+ prev_state = state;
- dev_vdbg(&mmc->class_dev, "data error: status=%08x\n", status);
+ switch (state) {
+ case STATE_IDLE:
+ break;
- atmci_set_completed(host, EVENT_DATA_ERROR);
- atmci_set_completed(host, EVENT_DATA_COMPLETE);
+ case STATE_SENDING_CMD:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_COMPLETE))
+ break;
- if (status & MCI_DTOE) {
- dev_dbg(&mmc->class_dev,
- "data timeout error\n");
- data->error = -ETIMEDOUT;
- } else if (status & MCI_DCRCE) {
- dev_dbg(&mmc->class_dev, "data CRC error\n");
- data->error = -EILSEQ;
- } else {
- dev_dbg(&mmc->class_dev,
- "data FIFO error (status=%08x)\n",
- status);
- data->error = -EIO;
- }
+ host->cmd = NULL;
+ atmci_set_completed(host, EVENT_CMD_COMPLETE);
+ atmci_command_complete(host, mrq->cmd);
+ if (!mrq->data || cmd->error) {
+ atmci_request_end(host, host->mrq);
+ goto unlock;
+ }
+
+ prev_state = state = STATE_SENDING_DATA;
+ /* fall through */
+
+ case STATE_SENDING_DATA:
+ if (atmci_test_and_clear_pending(host,
+ EVENT_DATA_ERROR)) {
+ atmci_stop_dma(host);
+ if (data->stop)
+ send_stop_cmd(host, data);
+ state = STATE_DATA_ERROR;
+ break;
+ }
- if (host->present && data->stop
- && atmci_is_completed(host, EVENT_CMD_COMPLETE)
- && !atmci_test_and_set_completed(
- host, EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, data);
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
- host->data = NULL;
- }
- if (atmci_test_and_clear_pending(host, EVENT_DATA_COMPLETE)) {
- atmci_set_completed(host, EVENT_DATA_COMPLETE);
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+ prev_state = state = STATE_DATA_BUSY;
+ /* fall through */
+
+ case STATE_DATA_BUSY:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_DATA_COMPLETE))
+ break;
- if (!atmci_is_completed(host, EVENT_DATA_ERROR)) {
- data->bytes_xfered = data->blocks * data->blksz;
- data->error = 0;
+ host->data = NULL;
+ atmci_set_completed(host, EVENT_DATA_COMPLETE);
+ status = host->data_status;
+ if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
+ if (status & MCI_DTOE) {
+ dev_dbg(&host->pdev->dev,
+ "data timeout error\n");
+ data->error = -ETIMEDOUT;
+ } else if (status & MCI_DCRCE) {
+ dev_dbg(&host->pdev->dev,
+ "data CRC error\n");
+ data->error = -EILSEQ;
+ } else {
+ dev_dbg(&host->pdev->dev,
+ "data FIFO error (status=%08x)\n",
+ status);
+ data->error = -EIO;
+ }
+ } else {
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+ }
+
+ if (!data->stop) {
+ atmci_request_end(host, host->mrq);
+ goto unlock;
+ }
+
+ prev_state = state = STATE_SENDING_STOP;
+ if (!data->error)
+ send_stop_cmd(host, data);
+ /* fall through */
+
+ case STATE_SENDING_STOP:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_COMPLETE))
+ break;
+
+ host->cmd = NULL;
+ atmci_command_complete(host, mrq->stop);
+ atmci_request_end(host, host->mrq);
+ goto unlock;
+
+ case STATE_DATA_ERROR:
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
+
+ state = STATE_DATA_BUSY;
+ break;
}
+ } while (state != prev_state);
- host->data = NULL;
- }
+ host->state = state;
- if (host->mrq && !host->cmd && !host->data)
- atmci_request_end(mmc, host->mrq);
+unlock:
+ spin_unlock(&host->lock);
}
static void atmci_read_data_pio(struct atmel_mci *host)
@@ -789,6 +1253,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)
nbytes += 4;
if (offset == sg->length) {
+ flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;
@@ -817,9 +1282,11 @@ static void atmci_read_data_pio(struct atmel_mci *host)
mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY
| ATMCI_DATA_ERROR_FLAGS));
host->data_status = status;
+ data->bytes_xfered += nbytes;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
- break;
+ return;
}
} while (status & MCI_RXRDY);
@@ -832,10 +1299,8 @@ done:
mci_writel(host, IDR, MCI_RXRDY);
mci_writel(host, IER, MCI_NOTBUSY);
data->bytes_xfered += nbytes;
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
- if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
- && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, data);
+ smp_wmb();
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
}
static void atmci_write_data_pio(struct atmel_mci *host)
@@ -888,9 +1353,11 @@ static void atmci_write_data_pio(struct atmel_mci *host)
mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY
| ATMCI_DATA_ERROR_FLAGS));
host->data_status = status;
+ data->bytes_xfered += nbytes;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
- break;
+ return;
}
} while (status & MCI_TXRDY);
@@ -903,38 +1370,26 @@ done:
mci_writel(host, IDR, MCI_TXRDY);
mci_writel(host, IER, MCI_NOTBUSY);
data->bytes_xfered += nbytes;
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
- if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
- && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
- send_stop_cmd(host->mmc, data);
+ smp_wmb();
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
}
-static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
+static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
{
- struct atmel_mci *host = mmc_priv(mmc);
-
mci_writel(host, IDR, MCI_CMDRDY);
- if (atmci_is_completed(host, EVENT_STOP_SENT)) {
- host->stop_status = status;
- atmci_set_pending(host, EVENT_STOP_COMPLETE);
- } else {
- host->cmd_status = status;
- atmci_set_pending(host, EVENT_CMD_COMPLETE);
- }
-
+ host->cmd_status = status;
+ smp_wmb();
+ atmci_set_pending(host, EVENT_CMD_COMPLETE);
tasklet_schedule(&host->tasklet);
}
static irqreturn_t atmci_interrupt(int irq, void *dev_id)
{
- struct mmc_host *mmc = dev_id;
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci *host = dev_id;
u32 status, mask, pending;
unsigned int pass_count = 0;
- spin_lock(&mmc->lock);
-
do {
status = mci_readl(host, SR);
mask = mci_readl(host, IMR);
@@ -946,13 +1401,18 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS
| MCI_RXRDY | MCI_TXRDY);
pending &= mci_readl(host, IMR);
+
host->data_status = status;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
}
if (pending & MCI_NOTBUSY) {
- mci_writel(host, IDR, (MCI_NOTBUSY
- | ATMCI_DATA_ERROR_FLAGS));
+ mci_writel(host, IDR,
+ ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY);
+ if (!host->data_status)
+ host->data_status = status;
+ smp_wmb();
atmci_set_pending(host, EVENT_DATA_COMPLETE);
tasklet_schedule(&host->tasklet);
}
@@ -962,18 +1422,15 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
atmci_write_data_pio(host);
if (pending & MCI_CMDRDY)
- atmci_cmd_interrupt(mmc, status);
+ atmci_cmd_interrupt(host, status);
} while (pass_count++ < 5);
- spin_unlock(&mmc->lock);
-
return pass_count ? IRQ_HANDLED : IRQ_NONE;
}
static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
{
- struct mmc_host *mmc = dev_id;
- struct atmel_mci *host = mmc_priv(mmc);
+ struct atmel_mci_slot *slot = dev_id;
/*
* Disable interrupts until the pin has stabilized and check
@@ -981,19 +1438,176 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
* middle of the timer routine when this interrupt triggers.
*/
disable_irq_nosync(irq);
- mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+ mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
return IRQ_HANDLED;
}
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+
+static inline struct atmel_mci *
+dma_client_to_atmel_mci(struct dma_client *client)
+{
+ return container_of(client, struct atmel_mci, dma.client);
+}
+
+static enum dma_state_client atmci_dma_event(struct dma_client *client,
+ struct dma_chan *chan, enum dma_state state)
+{
+ struct atmel_mci *host;
+ enum dma_state_client ret = DMA_NAK;
+
+ host = dma_client_to_atmel_mci(client);
+
+ switch (state) {
+ case DMA_RESOURCE_AVAILABLE:
+ spin_lock_bh(&host->lock);
+ if (!host->dma.chan) {
+ host->dma.chan = chan;
+ ret = DMA_ACK;
+ }
+ spin_unlock_bh(&host->lock);
+
+ if (ret == DMA_ACK)
+ dev_info(&host->pdev->dev,
+ "Using %s for DMA transfers\n",
+ chan->dev.bus_id);
+ break;
+
+ case DMA_RESOURCE_REMOVED:
+ spin_lock_bh(&host->lock);
+ if (host->dma.chan == chan) {
+ host->dma.chan = NULL;
+ ret = DMA_ACK;
+ }
+ spin_unlock_bh(&host->lock);
+
+ if (ret == DMA_ACK)
+ dev_info(&host->pdev->dev,
+ "Lost %s, falling back to PIO\n",
+ chan->dev.bus_id);
+ break;
+
+ default:
+ break;
+ }
+
+
+ return ret;
+}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int __init atmci_init_slot(struct atmel_mci *host,
+ struct mci_slot_pdata *slot_data, unsigned int id,
+ u32 sdc_reg)
+{
+ struct mmc_host *mmc;
+ struct atmel_mci_slot *slot;
+
+ mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ slot = mmc_priv(mmc);
+ slot->mmc = mmc;
+ slot->host = host;
+ slot->detect_pin = slot_data->detect_pin;
+ slot->wp_pin = slot_data->wp_pin;
+ slot->sdc_reg = sdc_reg;
+
+ mmc->ops = &atmci_ops;
+ mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
+ mmc->f_max = host->bus_hz / 2;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ if (slot_data->bus_width >= 4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ mmc->max_hw_segs = 64;
+ mmc->max_phys_segs = 64;
+ mmc->max_req_size = 32768 * 512;
+ mmc->max_blk_size = 32768;
+ mmc->max_blk_count = 512;
+
+ /* Assume card is present initially */
+ set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+ if (gpio_is_valid(slot->detect_pin)) {
+ if (gpio_request(slot->detect_pin, "mmc_detect")) {
+ dev_dbg(&mmc->class_dev, "no detect pin available\n");
+ slot->detect_pin = -EBUSY;
+ } else if (gpio_get_value(slot->detect_pin)) {
+ clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+ }
+ }
+
+ if (!gpio_is_valid(slot->detect_pin))
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+ if (gpio_is_valid(slot->wp_pin)) {
+ if (gpio_request(slot->wp_pin, "mmc_wp")) {
+ dev_dbg(&mmc->class_dev, "no WP pin available\n");
+ slot->wp_pin = -EBUSY;
+ }
+ }
+
+ host->slot[id] = slot;
+ mmc_add_host(mmc);
+
+ if (gpio_is_valid(slot->detect_pin)) {
+ int ret;
+
+ setup_timer(&slot->detect_timer, atmci_detect_change,
+ (unsigned long)slot);
+
+ ret = request_irq(gpio_to_irq(slot->detect_pin),
+ atmci_detect_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "mmc-detect", slot);
+ if (ret) {
+ dev_dbg(&mmc->class_dev,
+ "could not request IRQ %d for detect pin\n",
+ gpio_to_irq(slot->detect_pin));
+ gpio_free(slot->detect_pin);
+ slot->detect_pin = -EBUSY;
+ }
+ }
+
+ atmci_init_debugfs(slot);
+
+ return 0;
+}
+
+static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
+ unsigned int id)
+{
+ /* Debugfs stuff is cleaned up by mmc core */
+
+ set_bit(ATMCI_SHUTDOWN, &slot->flags);
+ smp_wmb();
+
+ mmc_remove_host(slot->mmc);
+
+ if (gpio_is_valid(slot->detect_pin)) {
+ int pin = slot->detect_pin;
+
+ free_irq(gpio_to_irq(pin), slot);
+ del_timer_sync(&slot->detect_timer);
+ gpio_free(pin);
+ }
+ if (gpio_is_valid(slot->wp_pin))
+ gpio_free(slot->wp_pin);
+
+ slot->host->slot[id] = NULL;
+ mmc_free_host(slot->mmc);
+}
+
static int __init atmci_probe(struct platform_device *pdev)
{
struct mci_platform_data *pdata;
- struct atmel_mci *host;
- struct mmc_host *mmc;
- struct resource *regs;
- int irq;
- int ret;
+ struct atmel_mci *host;
+ struct resource *regs;
+ unsigned int nr_slots;
+ int irq;
+ int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
@@ -1005,15 +1619,13 @@ static int __init atmci_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
- if (!mmc)
+ host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
+ if (!host)
return -ENOMEM;
- host = mmc_priv(mmc);
host->pdev = pdev;
- host->mmc = mmc;
- host->detect_pin = pdata->detect_pin;
- host->wp_pin = pdata->wp_pin;
+ spin_lock_init(&host->lock);
+ INIT_LIST_HEAD(&host->queue);
host->mck = clk_get(&pdev->dev, "mci_clk");
if (IS_ERR(host->mck)) {
@@ -1033,122 +1645,102 @@ static int __init atmci_probe(struct platform_device *pdev)
host->mapbase = regs->start;
- mmc->ops = &atmci_ops;
- mmc->f_min = (host->bus_hz + 511) / 512;
- mmc->f_max = host->bus_hz / 2;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- mmc->max_hw_segs = 64;
- mmc->max_phys_segs = 64;
- mmc->max_req_size = 32768 * 512;
- mmc->max_blk_size = 32768;
- mmc->max_blk_count = 512;
-
- tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
+ tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
- ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, mmc);
+ ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, host);
if (ret)
goto err_request_irq;
- /* Assume card is present if we don't have a detect pin */
- host->present = 1;
- if (gpio_is_valid(host->detect_pin)) {
- if (gpio_request(host->detect_pin, "mmc_detect")) {
- dev_dbg(&mmc->class_dev, "no detect pin available\n");
- host->detect_pin = -1;
- } else {
- host->present = !gpio_get_value(host->detect_pin);
- }
- }
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (pdata->dma_slave) {
+ struct dma_slave *slave = pdata->dma_slave;
- if (!gpio_is_valid(host->detect_pin))
- mmc->caps |= MMC_CAP_NEEDS_POLL;
+ slave->tx_reg = regs->start + MCI_TDR;
+ slave->rx_reg = regs->start + MCI_RDR;
- if (gpio_is_valid(host->wp_pin)) {
- if (gpio_request(host->wp_pin, "mmc_wp")) {
- dev_dbg(&mmc->class_dev, "no WP pin available\n");
- host->wp_pin = -1;
- }
+ /* Try to grab a DMA channel */
+ host->dma.client.event_callback = atmci_dma_event;
+ dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
+ host->dma.client.slave = slave;
+
+ dma_async_client_register(&host->dma.client);
+ dma_async_client_chan_request(&host->dma.client);
+ } else {
+ dev_notice(&pdev->dev, "DMA not available, using PIO\n");
}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
platform_set_drvdata(pdev, host);
- mmc_add_host(mmc);
-
- if (gpio_is_valid(host->detect_pin)) {
- setup_timer(&host->detect_timer, atmci_detect_change,
- (unsigned long)host);
-
- ret = request_irq(gpio_to_irq(host->detect_pin),
- atmci_detect_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mmc-detect", mmc);
- if (ret) {
- dev_dbg(&mmc->class_dev,
- "could not request IRQ %d for detect pin\n",
- gpio_to_irq(host->detect_pin));
- gpio_free(host->detect_pin);
- host->detect_pin = -1;
- }
+ /* We need at least one slot to succeed */
+ nr_slots = 0;
+ ret = -ENODEV;
+ if (pdata->slot[0].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[0],
+ MCI_SDCSEL_SLOT_A, 0);
+ if (!ret)
+ nr_slots++;
+ }
+ if (pdata->slot[1].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[1],
+ MCI_SDCSEL_SLOT_B, 1);
+ if (!ret)
+ nr_slots++;
}
- dev_info(&mmc->class_dev,
- "Atmel MCI controller at 0x%08lx irq %d\n",
- host->mapbase, irq);
+ if (!nr_slots)
+ goto err_init_slot;
- atmci_init_debugfs(host);
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
return 0;
+err_init_slot:
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (pdata->dma_slave)
+ dma_async_client_unregister(&host->dma.client);
+#endif
+ free_irq(irq, host);
err_request_irq:
iounmap(host->regs);
err_ioremap:
clk_put(host->mck);
err_clk_get:
- mmc_free_host(mmc);
+ kfree(host);
return ret;
}
static int __exit atmci_remove(struct platform_device *pdev)
{
- struct atmel_mci *host = platform_get_drvdata(pdev);
+ struct atmel_mci *host = platform_get_drvdata(pdev);
+ unsigned int i;
platform_set_drvdata(pdev, NULL);
- if (host) {
- /* Debugfs stuff is cleaned up by mmc core */
-
- if (gpio_is_valid(host->detect_pin)) {
- int pin = host->detect_pin;
-
- /* Make sure the timer doesn't enable the interrupt */
- host->detect_pin = -1;
- smp_wmb();
-
- free_irq(gpio_to_irq(pin), host->mmc);
- del_timer_sync(&host->detect_timer);
- gpio_free(pin);
- }
-
- mmc_remove_host(host->mmc);
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i])
+ atmci_cleanup_slot(host->slot[i], i);
+ }
- clk_enable(host->mck);
- mci_writel(host, IDR, ~0UL);
- mci_writel(host, CR, MCI_CR_MCIDIS);
- mci_readl(host, SR);
- clk_disable(host->mck);
+ clk_enable(host->mck);
+ mci_writel(host, IDR, ~0UL);
+ mci_writel(host, CR, MCI_CR_MCIDIS);
+ mci_readl(host, SR);
+ clk_disable(host->mck);
- if (gpio_is_valid(host->wp_pin))
- gpio_free(host->wp_pin);
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (host->dma.client.slave)
+ dma_async_client_unregister(&host->dma.client);
+#endif
- free_irq(platform_get_irq(pdev, 0), host->mmc);
- iounmap(host->regs);
+ free_irq(platform_get_irq(pdev, 0), host);
+ iounmap(host->regs);
- clk_put(host->mck);
+ clk_put(host->mck);
+ kfree(host);
- mmc_free_host(host->mmc);
- }
return 0;
}
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7503b81374e..07faf5412a1 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -95,8 +95,6 @@
* reads which takes nowhere near that long. Older cards may be able to use
* shorter timeouts ... but why bother?
*/
-#define readblock_timeout ktime_set(0, 100 * 1000 * 1000)
-#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000)
#define r1b_timeout ktime_set(3, 0)
@@ -220,9 +218,9 @@ mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
}
-static int mmc_spi_readtoken(struct mmc_spi_host *host)
+static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout)
{
- return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+ return mmc_spi_skip(host, timeout, 1, 0xff);
}
@@ -605,7 +603,8 @@ mmc_spi_setup_data_message(
* Return negative errno, else success.
*/
static int
-mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
+ ktime_t timeout)
{
struct spi_device *spi = host->spi;
int status, i;
@@ -673,7 +672,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
if (scratch->status[i] != 0)
return 0;
}
- return mmc_spi_wait_unbusy(host, writeblock_timeout);
+ return mmc_spi_wait_unbusy(host, timeout);
}
/*
@@ -693,7 +692,8 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
* STOP_TRANSMISSION command.
*/
static int
-mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
+ ktime_t timeout)
{
struct spi_device *spi = host->spi;
int status;
@@ -707,7 +707,7 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
return status;
status = scratch->status[0];
if (status == 0xff || status == 0)
- status = mmc_spi_readtoken(host);
+ status = mmc_spi_readtoken(host, timeout);
if (status == SPI_TOKEN_SINGLE) {
if (host->dma_dev) {
@@ -778,6 +778,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
struct scatterlist *sg;
unsigned n_sg;
int multiple = (data->blocks > 1);
+ u32 clock_rate;
+ ktime_t timeout;
if (data->flags & MMC_DATA_READ)
direction = DMA_FROM_DEVICE;
@@ -786,6 +788,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
mmc_spi_setup_data_message(host, multiple, direction);
t = &host->t;
+ if (t->speed_hz)
+ clock_rate = t->speed_hz;
+ else
+ clock_rate = spi->max_speed_hz;
+
+ timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns +
+ data->timeout_clks * 1000000 / clock_rate);
+
/* Handle scatterlist segments one at a time, with synch for
* each 512-byte block
*/
@@ -832,9 +842,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
t->len);
if (direction == DMA_TO_DEVICE)
- status = mmc_spi_writeblock(host, t);
+ status = mmc_spi_writeblock(host, t, timeout);
else
- status = mmc_spi_readblock(host, t);
+ status = mmc_spi_readblock(host, t, timeout);
if (status < 0)
break;
@@ -917,7 +927,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
if (scratch->status[tmp] != 0)
return;
}
- tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+ tmp = mmc_spi_wait_unbusy(host, timeout);
if (tmp < 0 && !data->error)
data->error = tmp;
}
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index fcb14c2346c..9bd7026b002 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -144,7 +144,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
SDHCI_QUIRK_32BIT_DMA_SIZE |
SDHCI_QUIRK_32BIT_ADMA_SIZE |
SDHCI_QUIRK_RESET_AFTER_REQUEST |
- SDHCI_QUIRK_BROKEN_SMALL_PIO;
+ SDHCI_QUIRK_BROKEN_SMALL_PIO |
+ SDHCI_QUIRK_FORCE_HIGHSPEED;
}
/*
@@ -326,7 +327,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
{
.vendor = PCI_VENDOR_ID_MARVELL,
- .device = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+ .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_cafe,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e3a8133560a..30f64b1f235 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -177,7 +177,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
{
unsigned long flags;
size_t blksize, len, chunk;
- u32 scratch;
+ u32 uninitialized_var(scratch);
u8 *buf;
DBG("PIO reading\n");
@@ -1154,7 +1154,7 @@ static void sdhci_tasklet_card(unsigned long param)
spin_unlock_irqrestore(&host->lock, flags);
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+ mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
static void sdhci_tasklet_finish(unsigned long param)
@@ -1266,9 +1266,31 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
SDHCI_INT_INDEX))
host->cmd->error = -EILSEQ;
- if (host->cmd->error)
+ if (host->cmd->error) {
tasklet_schedule(&host->finish_tasklet);
- else if (intmask & SDHCI_INT_RESPONSE)
+ return;
+ }
+
+ /*
+ * The host can send and interrupt when the busy state has
+ * ended, allowing us to wait without wasting CPU cycles.
+ * Unfortunately this is overloaded on the "data complete"
+ * interrupt, so we need to take some care when handling
+ * it.
+ *
+ * Note: The 1.0 specification is a bit ambiguous about this
+ * feature so there might be some problems with older
+ * controllers.
+ */
+ if (host->cmd->flags & MMC_RSP_BUSY) {
+ if (host->cmd->data)
+ DBG("Cannot wait for busy signal when also "
+ "doing a data transfer");
+ else
+ return;
+ }
+
+ if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
}
@@ -1278,11 +1300,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (!host->data) {
/*
- * A data end interrupt is sent together with the response
- * for the stop command.
+ * The "data complete" interrupt is also used to
+ * indicate that a busy state has ended. See comment
+ * above in sdhci_cmd_irq().
*/
- if (intmask & SDHCI_INT_DATA_END)
- return;
+ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+ if (intmask & SDHCI_INT_DATA_END) {
+ sdhci_finish_command(host);
+ return;
+ }
+ }
printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
"though no data operation was in progress.\n",
@@ -1604,7 +1631,8 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->f_max = host->max_clk;
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
- if (caps & SDHCI_CAN_DO_HISPD)
+ if ((caps & SDHCI_CAN_DO_HISPD) ||
+ (host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
mmc->ocr_avail = 0;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 197d4a05f4a..31f4b1528e7 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -208,6 +208,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
/* Controller has an issue with buffer bits for small transfers */
#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
+/* Controller supports high speed but doesn't have the caps bit set */
+#define SDHCI_QUIRK_FORCE_HIGHSPEED (1<<14)
int irq; /* Device IRQ */
void __iomem * ioaddr; /* Mapped address */
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 0d7c88396c8..fd7a1017399 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -1,13 +1,10 @@
-/*
- *
- * sun_uflash - Driver implementation for user-programmable flash
- * present on many Sun Microsystems SME boardsets.
+/* sun_uflash.c - Driver for user-programmable flash on
+ * Sun Microsystems SME boardsets.
*
* This driver does NOT provide access to the OBP-flash for
* safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
*
* Copyright (c) 2001 Eric Brower (ebrower@usa.net)
- *
*/
#include <linux/kernel.h>
@@ -16,8 +13,8 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/prom.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -26,67 +23,65 @@
#include <linux/mtd/map.h>
#define UFLASH_OBPNAME "flashprom"
-#define UFLASH_DEVNAME "userflash"
+#define DRIVER_NAME "sun_uflash"
+#define PFX DRIVER_NAME ": "
#define UFLASH_WINDOW_SIZE 0x200000
#define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */
MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE("userflash");
+MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
-static LIST_HEAD(device_list);
struct uflash_dev {
const char *name; /* device name */
struct map_info map; /* mtd map info */
struct mtd_info *mtd; /* mtd info */
};
-
struct map_info uflash_map_templ = {
.name = "SUNW,???-????",
.size = UFLASH_WINDOW_SIZE,
.bankwidth = UFLASH_BUSWIDTH,
};
-int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
+int uflash_devinit(struct of_device *op, struct device_node *dp)
{
struct uflash_dev *up;
- struct resource *res;
- res = &edev->resource[0];
-
- if (edev->num_addrs != 1) {
+ if (op->resource[1].flags) {
/* Non-CFI userflash device-- once I find one we
* can work on supporting it.
*/
- printk("%s: unsupported device at 0x%llx (%d regs): " \
- "email ebrower@usa.net\n",
- dp->full_name, (unsigned long long)res->start,
- edev->num_addrs);
+ printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n",
+ dp->full_name, (unsigned long long)op->resource[0].start);
return -ENODEV;
}
up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
- if (!up)
+ if (!up) {
+ printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n");
return -ENOMEM;
+ }
/* copy defaults and tweak parameters */
memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
- up->map.size = (res->end - res->start) + 1UL;
+
+ up->map.size = resource_size(&op->resource[0]);
up->name = of_get_property(dp, "model", NULL);
if (up->name && 0 < strlen(up->name))
up->map.name = (char *)up->name;
- up->map.phys = res->start;
+ up->map.phys = op->resource[0].start;
- up->map.virt = ioremap_nocache(res->start, up->map.size);
+ up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size,
+ DRIVER_NAME);
if (!up->map.virt) {
- printk("%s: Failed to map device.\n", dp->full_name);
+ printk(KERN_ERR PFX "Failed to map device.\n");
kfree(up);
return -EINVAL;
@@ -97,7 +92,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
/* MTD registration */
up->mtd = do_map_probe("cfi_probe", &up->map);
if (!up->mtd) {
- iounmap(up->map.virt);
+ of_iounmap(&op->resource[0], up->map.virt, up->map.size);
kfree(up);
return -ENXIO;
@@ -107,32 +102,34 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
add_mtd_device(up->mtd);
- dev_set_drvdata(&edev->ofdev.dev, up);
+ dev_set_drvdata(&op->dev, up);
return 0;
}
-static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match)
{
- struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
- struct device_node *dp = dev->node;
+ struct device_node *dp = op->node;
- if (of_find_property(dp, "user", NULL))
+ /* Flashprom must have the "user" property in order to
+ * be used by this driver.
+ */
+ if (!of_find_property(dp, "user", NULL))
return -ENODEV;
- return uflash_devinit(edev, dp);
+ return uflash_devinit(op, dp);
}
-static int __devexit uflash_remove(struct of_device *dev)
+static int __devexit uflash_remove(struct of_device *op)
{
- struct uflash_dev *up = dev_get_drvdata(&dev->dev);
+ struct uflash_dev *up = dev_get_drvdata(&op->dev);
if (up->mtd) {
del_mtd_device(up->mtd);
map_destroy(up->mtd);
}
if (up->map.virt) {
- iounmap(up->map.virt);
+ of_iounmap(&op->resource[0], up->map.virt, up->map.size);
up->map.virt = NULL;
}
@@ -141,7 +138,7 @@ static int __devexit uflash_remove(struct of_device *dev)
return 0;
}
-static struct of_device_id uflash_match[] = {
+static const struct of_device_id uflash_match[] = {
{
.name = UFLASH_OBPNAME,
},
@@ -151,7 +148,7 @@ static struct of_device_id uflash_match[] = {
MODULE_DEVICE_TABLE(of, uflash_match);
static struct of_platform_driver uflash_driver = {
- .name = UFLASH_DEVNAME,
+ .name = DRIVER_NAME,
.match_table = uflash_match,
.probe = uflash_probe,
.remove = __devexit_p(uflash_remove),
@@ -159,7 +156,7 @@ static struct of_platform_driver uflash_driver = {
static int __init uflash_init(void)
{
- return of_register_driver(&uflash_driver, &ebus_bus_type);
+ return of_register_driver(&uflash_driver, &of_bus_type);
}
static void __exit uflash_exit(void)
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 95345d05157..b8064bf3aee 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -1,6 +1,9 @@
/*
* Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
*
+ * The data sheet for this device can be found at:
+ * http://www.marvell.com/products/pcconn/88ALP01.jsp
+ *
* Copyright © 2006 Red Hat, Inc.
* Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
*/
@@ -842,7 +845,8 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
}
static struct pci_device_id cafe_nand_tbl[] = {
- { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_NAND,
+ PCI_ANY_ID, PCI_ANY_ID },
{ }
};
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 7b92201a7b5..019b13c08ae 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -94,8 +94,8 @@ static irqreturn_t au1000_interrupt(int, void *);
static void au1000_tx_timeout(struct net_device *);
static void set_rx_mode(struct net_device *);
static int au1000_ioctl(struct net_device *, struct ifreq *, int);
-static int mdio_read(struct net_device *, int, int);
-static void mdio_write(struct net_device *, int, int, u16);
+static int au1000_mdio_read(struct net_device *, int, int);
+static void au1000_mdio_write(struct net_device *, int, int, u16);
static void au1000_adjust_link(struct net_device *);
static void enable_mac(struct net_device *, int);
@@ -191,7 +191,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
/*
* MII operations
*/
-static int mdio_read(struct net_device *dev, int phy_addr, int reg)
+static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
volatile u32 *const mii_control_reg = &aup->mac->mii_control;
@@ -225,7 +225,8 @@ static int mdio_read(struct net_device *dev, int phy_addr, int reg)
return (int)*mii_data_reg;
}
-static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value)
+static void au1000_mdio_write(struct net_device *dev, int phy_addr,
+ int reg, u16 value)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
volatile u32 *const mii_control_reg = &aup->mac->mii_control;
@@ -249,7 +250,7 @@ static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value)
*mii_control_reg = mii_control;
}
-static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
{
/* WARNING: bus->phy_map[phy_addr].attached_dev == dev does
* _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */
@@ -257,21 +258,21 @@ static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
enable_mac(dev, 0); /* make sure the MAC associated with this
* mii_bus is enabled */
- return mdio_read(dev, phy_addr, regnum);
+ return au1000_mdio_read(dev, phy_addr, regnum);
}
-static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
- u16 value)
+static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+ u16 value)
{
struct net_device *const dev = bus->priv;
enable_mac(dev, 0); /* make sure the MAC associated with this
* mii_bus is enabled */
- mdio_write(dev, phy_addr, regnum, value);
+ au1000_mdio_write(dev, phy_addr, regnum, value);
return 0;
}
-static int mdiobus_reset(struct mii_bus *bus)
+static int au1000_mdiobus_reset(struct mii_bus *bus)
{
struct net_device *const dev = bus->priv;
@@ -703,9 +704,9 @@ static struct net_device * au1000_probe(int port_num)
goto err_out;
aup->mii_bus->priv = dev;
- aup->mii_bus->read = mdiobus_read;
- aup->mii_bus->write = mdiobus_write;
- aup->mii_bus->reset = mdiobus_reset;
+ aup->mii_bus->read = au1000_mdiobus_read;
+ aup->mii_bus->write = au1000_mdiobus_write;
+ aup->mii_bus->reset = au1000_mdiobus_reset;
aup->mii_bus->name = "au1000_eth_mii";
snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index a0d41c5d97d..b458d607a9c 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -253,7 +253,7 @@ init_error:
* MII operations
*/
/* Wait until the previous MDC/MDIO transaction has completed */
-static void mdio_poll(void)
+static void bfin_mdio_poll(void)
{
int timeout_cnt = MAX_TIMEOUT_CNT;
@@ -269,25 +269,25 @@ static void mdio_poll(void)
}
/* Read an off-chip register in a PHY through the MDC/MDIO port */
-static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+static int bfin_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
{
- mdio_poll();
+ bfin_mdio_poll();
/* read mode */
bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
SET_REGAD((u16) regnum) |
STABUSY);
- mdio_poll();
+ bfin_mdio_poll();
return (int) bfin_read_EMAC_STADAT();
}
/* Write an off-chip register in a PHY through the MDC/MDIO port */
-static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
- u16 value)
+static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+ u16 value)
{
- mdio_poll();
+ bfin_mdio_poll();
bfin_write_EMAC_STADAT((u32) value);
@@ -297,12 +297,12 @@ static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
STAOP |
STABUSY);
- mdio_poll();
+ bfin_mdio_poll();
return 0;
}
-static int mdiobus_reset(struct mii_bus *bus)
+static int bfin_mdiobus_reset(struct mii_bus *bus)
{
return 0;
}
@@ -818,7 +818,7 @@ static void bfin_mac_enable(void)
bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
/* Wait MII done */
- mdio_poll();
+ bfin_mdio_poll();
/* We enable only RX here */
/* ASTP : Enable Automatic Pad Stripping
@@ -1063,9 +1063,9 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
goto out_err_mdiobus_alloc;
lp->mii_bus->priv = ndev;
- lp->mii_bus->read = mdiobus_read;
- lp->mii_bus->write = mdiobus_write;
- lp->mii_bus->reset = mdiobus_reset;
+ lp->mii_bus->read = bfin_mdiobus_read;
+ lp->mii_bus->write = bfin_mdiobus_write;
+ lp->mii_bus->reset = bfin_mdiobus_reset;
lp->mii_bus->name = "bfin_mac_mdio";
snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0");
lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 3bafaede791..fac82152e4c 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1047,6 +1047,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_LLTX;
+ netdev->vlan_features |= NETIF_F_TSO;
+ netdev->vlan_features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_HW_CSUM;
+ netdev->vlan_features |= NETIF_F_SG;
+
adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw);
/* initialize eeprom parameters */
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 5f9a1313fa3..156f159aafb 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -21,7 +21,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 06e682334c7..3ad7589d6a1 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1,6 +1,6 @@
/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
- * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net)
*/
static char version[] =
@@ -22,6 +22,9 @@ static char version[] =
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <net/dst.h>
#include <net/arp.h>
@@ -33,7 +36,6 @@ static char version[] =
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/auxio.h>
@@ -243,7 +245,8 @@ static void myri_clean_rings(struct myri_eth *mp)
u32 dma_addr;
dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+ dma_unmap_single(&mp->myri_op->dev, dma_addr,
+ RX_ALLOC_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb(mp->rx_skbs[i]);
mp->rx_skbs[i] = NULL;
}
@@ -259,7 +262,9 @@ static void myri_clean_rings(struct myri_eth *mp)
u32 dma_addr;
dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);
+ dma_unmap_single(&mp->myri_op->dev, dma_addr,
+ (skb->len + 3) & ~3,
+ DMA_TO_DEVICE);
dev_kfree_skb(mp->tx_skbs[i]);
mp->tx_skbs[i] = NULL;
}
@@ -288,7 +293,9 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
skb->dev = dev;
skb_put(skb, RX_ALLOC_SIZE);
- dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+ dma_addr = dma_map_single(&mp->myri_op->dev,
+ skb->data, RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr);
sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len);
sbus_writel(i, &rxd[i].ctx);
@@ -344,7 +351,8 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
DTX(("SKB[%d] ", entry));
dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);
- sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
+ dma_unmap_single(&mp->myri_op->dev, dma_addr,
+ skb->len, DMA_TO_DEVICE);
dev_kfree_skb(skb);
mp->tx_skbs[entry] = NULL;
dev->stats.tx_packets++;
@@ -423,9 +431,9 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
/* Check for errors. */
DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
- sbus_dma_sync_single_for_cpu(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE, DMA_FROM_DEVICE);
if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
DRX(("ERROR["));
dev->stats.rx_errors++;
@@ -442,10 +450,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
drops++;
DRX(("DROP "));
dev->stats.rx_dropped++;
- sbus_dma_sync_single_for_device(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
sbus_writel(index, &rxd->ctx);
sbus_writel(1, &rxd->num_sg);
@@ -464,17 +472,17 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
DRX(("skb_alloc(FAILED) "));
goto drop_it;
}
- sbus_unmap_single(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_unmap_single(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
mp->rx_skbs[index] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, RX_ALLOC_SIZE);
- dma_addr = sbus_map_single(mp->myri_sdev,
- new_skb->data,
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_addr = dma_map_single(&mp->myri_op->dev,
+ new_skb->data,
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
sbus_writel(dma_addr, &rxd->myri_scatters[0].addr);
sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
sbus_writel(index, &rxd->ctx);
@@ -500,10 +508,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
/* Reuse original ring buffer. */
DRX(("reuse "));
- sbus_dma_sync_single_for_device(mp->myri_sdev,
- sbus_readl(&rxd->myri_scatters[0].addr),
- RX_ALLOC_SIZE,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&mp->myri_op->dev,
+ sbus_readl(&rxd->myri_scatters[0].addr),
+ RX_ALLOC_SIZE,
+ DMA_FROM_DEVICE);
sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
sbus_writel(index, &rxd->ctx);
sbus_writel(1, &rxd->num_sg);
@@ -652,7 +660,8 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]);
}
- dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+ dma_addr = dma_map_single(&mp->myri_op->dev, skb->data,
+ len, DMA_TO_DEVICE);
sbus_writel(dma_addr, &txd->myri_gathers[0].addr);
sbus_writel(len, &txd->myri_gathers[0].len);
sbus_writel(1, &txd->num_sg);
@@ -891,30 +900,30 @@ static const struct header_ops myri_header_ops = {
.cache_update = myri_header_cache_update,
};
-static int __devinit myri_ether_init(struct sbus_dev *sdev)
+static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- static int num;
+ struct device_node *dp = op->node;
static unsigned version_printed;
struct net_device *dev;
- struct myri_eth *mp;
- unsigned char prop_buf[32];
- int i;
DECLARE_MAC_BUF(mac);
+ struct myri_eth *mp;
+ const void *prop;
+ static int num;
+ int i, len;
- DET(("myri_ether_init(%p,%d):\n", sdev, num));
+ DET(("myri_ether_init(%p,%d):\n", op, num));
dev = alloc_etherdev(sizeof(struct myri_eth));
-
if (!dev)
return -ENOMEM;
if (version_printed++ == 0)
printk(version);
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
- mp = (struct myri_eth *) dev->priv;
+ mp = netdev_priv(dev);
spin_lock_init(&mp->irq_lock);
- mp->myri_sdev = sdev;
+ mp->myri_op = op;
/* Clean out skb arrays. */
for (i = 0; i < (RX_RING_SIZE + 1); i++)
@@ -924,55 +933,44 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
mp->tx_skbs[i] = NULL;
/* First check for EEPROM information. */
- i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info",
- (char *)&mp->eeprom, sizeof(struct myri_eeprom));
- DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i));
- if (i == 0 || i == -1) {
+ prop = of_get_property(dp, "myrinet-eeprom-info", &len);
+
+ if (prop)
+ memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom));
+ if (!prop) {
/* No eeprom property, must cook up the values ourselves. */
DET(("No EEPROM: "));
mp->eeprom.bus_type = BUS_TYPE_SBUS;
- mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0);
- mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0);
- mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0);
- DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers,
- mp->eeprom.cval, mp->eeprom.ramsz));
- if (mp->eeprom.cpuvers == 0) {
- DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3));
+ mp->eeprom.cpuvers =
+ of_getintprop_default(dp, "cpu_version", 0);
+ mp->eeprom.cval =
+ of_getintprop_default(dp, "clock_value", 0);
+ mp->eeprom.ramsz = of_getintprop_default(dp, "sram_size", 0);
+ if (!mp->eeprom.cpuvers)
mp->eeprom.cpuvers = CPUVERS_2_3;
- }
- if (mp->eeprom.cpuvers < CPUVERS_3_0) {
- DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n"));
+ if (mp->eeprom.cpuvers < CPUVERS_3_0)
mp->eeprom.cval = 0;
- }
- if (mp->eeprom.ramsz == 0) {
- DET(("EEPROM: ramsz == 0, setting to 128k\n"));
+ if (!mp->eeprom.ramsz)
mp->eeprom.ramsz = (128 * 1024);
- }
- i = prom_getproperty(sdev->prom_node, "myrinet-board-id",
- &prop_buf[0], 10);
- DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i));
- if ((i != 0) && (i != -1))
- memcpy(&mp->eeprom.id[0], &prop_buf[0], 6);
+
+ prop = of_get_property(dp, "myrinet-board-id", &len);
+ if (prop)
+ memcpy(&mp->eeprom.id[0], prop, 6);
else
set_boardid_from_idprom(mp, num);
- i = prom_getproperty(sdev->prom_node, "fpga_version",
- &mp->eeprom.fvers[0], 32);
- DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i));
- if (i == 0 || i == -1)
+
+ prop = of_get_property(dp, "fpga_version", &len);
+ if (prop)
+ memcpy(&mp->eeprom.fvers[0], prop, 32);
+ else
memset(&mp->eeprom.fvers[0], 0, 32);
if (mp->eeprom.cpuvers == CPUVERS_4_1) {
- DET(("EEPROM: cpuvers CPUVERS_4_1, "));
- if (mp->eeprom.ramsz == (128 * 1024)) {
- DET(("ramsize 128k, setting to 256k, "));
+ if (mp->eeprom.ramsz == (128 * 1024))
mp->eeprom.ramsz = (256 * 1024);
- }
- if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){
- DET(("changing cval from %08x to %08x ",
- mp->eeprom.cval, 0x50e450e4));
+ if ((mp->eeprom.cval == 0x40414041) ||
+ (mp->eeprom.cval == 0x90449044))
mp->eeprom.cval = 0x50e450e4;
- }
- DET(("\n"));
}
}
#ifdef DEBUG_DETECT
@@ -991,8 +989,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
* XXX only a valid version for PCI cards? Ask feldy...
*/
DET(("Mapping regs for cpuvers < CPUVERS_4_0\n"));
- mp->regs = sbus_ioremap(&sdev->resource[0], 0,
- mp->reg_size, "MyriCOM Regs");
+ mp->regs = of_ioremap(&op->resource[0], 0,
+ mp->reg_size, "MyriCOM Regs");
if (!mp->regs) {
printk("MyriCOM: Cannot map MyriCOM registers.\n");
goto err;
@@ -1001,13 +999,12 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
mp->lregs = mp->lanai + (0x10000 * 2);
} else {
DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n"));
- mp->cregs = sbus_ioremap(&sdev->resource[0], 0,
- PAGE_SIZE, "MyriCOM Control Regs");
- mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024),
+ mp->cregs = of_ioremap(&op->resource[0], 0,
+ PAGE_SIZE, "MyriCOM Control Regs");
+ mp->lregs = of_ioremap(&op->resource[0], (256 * 1024),
PAGE_SIZE, "MyriCOM LANAI Regs");
- mp->lanai =
- sbus_ioremap(&sdev->resource[0], (512 * 1024),
- mp->eeprom.ramsz, "MyriCOM SRAM");
+ mp->lanai = of_ioremap(&op->resource[0], (512 * 1024),
+ mp->eeprom.ramsz, "MyriCOM SRAM");
}
DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n",
mp->cregs, mp->lregs, mp->lanai));
@@ -1039,16 +1036,15 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
myri_reset_on(mp->cregs);
/* Get the supported DVMA burst sizes from our SBUS. */
- mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node,
- "burst-sizes", 0x00);
-
- if (!sbus_can_burst64(sdev))
+ mp->myri_bursts = of_getintprop_default(dp->parent,
+ "burst-sizes", 0x00);
+ if (!sbus_can_burst64())
mp->myri_bursts &= ~(DMA_BURST64);
DET(("MYRI bursts %02x\n", mp->myri_bursts));
/* Encode SBUS interrupt level in second control register. */
- i = prom_getint(sdev->prom_node, "interrupts");
+ i = of_getintprop_default(dp, "interrupts", 0);
if (i == 0)
i = 4;
DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n",
@@ -1063,7 +1059,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
dev->tx_timeout = &myri_tx_timeout;
dev->watchdog_timeo = 5*HZ;
dev->set_multicast_list = &myri_set_multicast;
- dev->irq = sdev->irqs[0];
+ dev->irq = op->irqs[0];
/* Register interrupt handler now. */
DET(("Requesting MYRIcom IRQ line.\n"));
@@ -1088,7 +1084,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
goto err_free_irq;
}
- dev_set_drvdata(&sdev->ofdev.dev, mp);
+ dev_set_drvdata(&op->dev, mp);
num++;
@@ -1105,17 +1101,9 @@ err:
return -ENODEV;
}
-
-static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
- return myri_ether_init(sdev);
-}
-
-static int __devexit myri_sbus_remove(struct of_device *dev)
+static int __devexit myri_sbus_remove(struct of_device *op)
{
- struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+ struct myri_eth *mp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = mp->dev;
unregister_netdev(net_dev);
@@ -1123,21 +1111,21 @@ static int __devexit myri_sbus_remove(struct of_device *dev)
free_irq(net_dev->irq, net_dev);
if (mp->eeprom.cpuvers < CPUVERS_4_0) {
- sbus_iounmap(mp->regs, mp->reg_size);
+ of_iounmap(&op->resource[0], mp->regs, mp->reg_size);
} else {
- sbus_iounmap(mp->cregs, PAGE_SIZE);
- sbus_iounmap(mp->lregs, (256 * 1024));
- sbus_iounmap(mp->lanai, (512 * 1024));
+ of_iounmap(&op->resource[0], mp->cregs, PAGE_SIZE);
+ of_iounmap(&op->resource[0], mp->lregs, (256 * 1024));
+ of_iounmap(&op->resource[0], mp->lanai, (512 * 1024));
}
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id myri_sbus_match[] = {
+static const struct of_device_id myri_sbus_match[] = {
{
.name = "MYRICOM,mlanai",
},
@@ -1158,7 +1146,7 @@ static struct of_platform_driver myri_sbus_driver = {
static int __init myri_sbus_init(void)
{
- return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&myri_sbus_driver, &of_bus_type);
}
static void __exit myri_sbus_exit(void)
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 5d93fcc95d5..ff363e95d9c 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -288,7 +288,7 @@ struct myri_eth {
struct myri_eeprom eeprom; /* Local copy of EEPROM. */
unsigned int reg_size; /* Size of register space. */
unsigned int shmem_base; /* Offset to shared ram. */
- struct sbus_dev *myri_sdev; /* Our SBUS device struct. */
+ struct of_device *myri_op; /* Our OF device struct. */
};
/* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index e3be81eba8a..ebc81270290 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -9130,7 +9130,7 @@ static int __devexit niu_of_remove(struct of_device *op)
return 0;
}
-static struct of_device_id niu_match[] = {
+static const struct of_device_id niu_match[] = {
{
.name = "network",
.compatible = "SUNW,niusl",
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 6457f8c4fda..b62fbd4bf00 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -29,7 +29,6 @@
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 3af822b6226..297877b68c4 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -36,7 +36,6 @@
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index bdae2c59a75..c821da21d8e 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2154,6 +2154,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
spin_lock_init(&tp->lock);
+ tp->mmio_addr = ioaddr;
+
rtl_init_mac_address(tp, ioaddr);
/* Get MAC address */
@@ -2186,7 +2188,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
tp->intr_mask = 0xffff;
- tp->mmio_addr = ioaddr;
tp->align = cfg->align;
tp->hw_start = cfg->hw_start;
tp->intr_event = cfg->intr_event;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 3805b9318be..3813d15e2df 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -3034,7 +3034,8 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
- if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+ if ((wol->wolopts & ~sky2_wol_supported(sky2->hw))
+ || !device_can_wakeup(&hw->pdev->dev))
return -EOPNOTSUPP;
sky2->wol = wol->wolopts;
@@ -3045,6 +3046,8 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
sky2_write32(hw, B0_CTST, sky2->wol
? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
+ device_set_wakeup_enable(&hw->pdev->dev, sky2->wol);
+
if (!netif_running(dev))
sky2_wol_init(sky2);
return 0;
@@ -4179,18 +4182,6 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
return err;
}
-static int __devinit pci_wake_enabled(struct pci_dev *dev)
-{
- int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- u16 value;
-
- if (!pm)
- return 0;
- if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
- return 0;
- return value & PCI_PM_CTRL_PME_ENABLE;
-}
-
/*
* Read and parse the first part of Vital Product Data
*/
@@ -4314,7 +4305,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
}
}
- wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+ wol_default = device_may_wakeup(&pdev->dev) ? WAKE_MAGIC : 0;
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 02cc064c2c8..8aa7460ef0e 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -685,8 +685,10 @@ static void smc911x_phy_detect(struct net_device *dev)
* PHY#1 to PHY#31, and then PHY#0 last.
*/
switch(lp->version) {
- case 0x115:
- case 0x117:
+ case CHIP_9115:
+ case CHIP_9117:
+ case CHIP_9215:
+ case CHIP_9217:
cfg = SMC_GET_HW_CFG(lp);
if (cfg & HW_CFG_EXT_PHY_DET_) {
cfg &= ~HW_CFG_PHY_CLK_SEL_;
@@ -722,6 +724,9 @@ static void smc911x_phy_detect(struct net_device *dev)
break;
}
}
+ if (phyaddr < 32)
+ /* Found an external PHY */
+ break;
}
default:
/* Internal media only */
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 2abfc284519..bf6240f23f5 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -666,10 +666,13 @@ smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr,
#define LAN911X_INTERNAL_PHY_ID (0x0007C000)
/* Chip ID values */
-#define CHIP_9115 0x115
-#define CHIP_9116 0x116
-#define CHIP_9117 0x117
-#define CHIP_9118 0x118
+#define CHIP_9115 0x0115
+#define CHIP_9116 0x0116
+#define CHIP_9117 0x0117
+#define CHIP_9118 0x0118
+#define CHIP_9215 0x115A
+#define CHIP_9217 0x117A
+#define CHIP_9218 0x118A
struct chip_id {
u16 id;
@@ -681,6 +684,9 @@ static const struct chip_id chip_ids[] = {
{ CHIP_9116, "LAN9116" },
{ CHIP_9117, "LAN9117" },
{ CHIP_9118, "LAN9118" },
+ { CHIP_9215, "LAN9215" },
+ { CHIP_9217, "LAN9217" },
+ { CHIP_9218, "LAN9218" },
{ 0, NULL },
};
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 31e7384e312..018d0fca942 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1,7 +1,6 @@
-/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
- * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
+/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
*
- * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -23,6 +22,9 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/auxio.h>
#include <asm/byteorder.h>
@@ -32,15 +34,14 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#include <asm/system.h>
#include "sunbmac.h"
#define DRV_NAME "sunbmac"
-#define DRV_VERSION "2.0"
-#define DRV_RELDATE "11/24/03"
-#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION "2.1"
+#define DRV_RELDATE "August 26, 2008"
+#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -96,8 +97,8 @@ static int qec_global_reset(void __iomem *gregs)
static void qec_init(struct bigmac *bp)
{
+ struct of_device *qec_op = bp->qec_op;
void __iomem *gregs = bp->gregs;
- struct sbus_dev *qec_sdev = bp->qec_sdev;
u8 bsizes = bp->bigmac_bursts;
u32 regval;
@@ -112,13 +113,13 @@ static void qec_init(struct bigmac *bp)
sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE);
/* All of memsize is given to bigmac. */
- sbus_writel(qec_sdev->reg_addrs[1].reg_size,
+ sbus_writel(resource_size(&qec_op->resource[1]),
gregs + GLOB_MSIZE);
/* Half to the transmitter, half to the receiver. */
- sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+ sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
gregs + GLOB_TSIZE);
- sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+ sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
gregs + GLOB_RSIZE);
}
@@ -239,9 +240,10 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq)
skb_reserve(skb, 34);
bb->be_rxd[i].rx_addr =
- sbus_map_single(bp->bigmac_sdev, skb->data,
- RX_BUF_ALLOC_SIZE - 34,
- SBUS_DMA_FROMDEVICE);
+ dma_map_single(&bp->bigmac_op->dev,
+ skb->data,
+ RX_BUF_ALLOC_SIZE - 34,
+ DMA_FROM_DEVICE);
bb->be_rxd[i].rx_flags =
(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
}
@@ -776,9 +778,9 @@ static void bigmac_tx(struct bigmac *bp)
skb = bp->tx_skbs[elem];
bp->enet_stats.tx_packets++;
bp->enet_stats.tx_bytes += skb->len;
- sbus_unmap_single(bp->bigmac_sdev,
- this->tx_addr, skb->len,
- SBUS_DMA_TODEVICE);
+ dma_unmap_single(&bp->bigmac_op->dev,
+ this->tx_addr, skb->len,
+ DMA_TO_DEVICE);
DTX(("skb(%p) ", skb));
bp->tx_skbs[elem] = NULL;
@@ -831,18 +833,19 @@ static void bigmac_rx(struct bigmac *bp)
drops++;
goto drop_it;
}
- sbus_unmap_single(bp->bigmac_sdev,
- this->rx_addr,
- RX_BUF_ALLOC_SIZE - 34,
- SBUS_DMA_FROMDEVICE);
+ dma_unmap_single(&bp->bigmac_op->dev,
+ this->rx_addr,
+ RX_BUF_ALLOC_SIZE - 34,
+ DMA_FROM_DEVICE);
bp->rx_skbs[elem] = new_skb;
new_skb->dev = bp->dev;
skb_put(new_skb, ETH_FRAME_LEN);
skb_reserve(new_skb, 34);
- this->rx_addr = sbus_map_single(bp->bigmac_sdev,
- new_skb->data,
- RX_BUF_ALLOC_SIZE - 34,
- SBUS_DMA_FROMDEVICE);
+ this->rx_addr =
+ dma_map_single(&bp->bigmac_op->dev,
+ new_skb->data,
+ RX_BUF_ALLOC_SIZE - 34,
+ DMA_FROM_DEVICE);
this->rx_flags =
(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
@@ -857,13 +860,13 @@ static void bigmac_rx(struct bigmac *bp)
}
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
- sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
- this->rx_addr, len,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&bp->bigmac_op->dev,
+ this->rx_addr, len,
+ DMA_FROM_DEVICE);
skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len);
- sbus_dma_sync_single_for_device(bp->bigmac_sdev,
- this->rx_addr, len,
- SBUS_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&bp->bigmac_op->dev,
+ this->rx_addr, len,
+ DMA_FROM_DEVICE);
/* Reuse original ring buffer. */
this->rx_flags =
@@ -959,7 +962,8 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 mapping;
len = skb->len;
- mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+ mapping = dma_map_single(&bp->bigmac_op->dev, skb->data,
+ len, DMA_TO_DEVICE);
/* Avoid a race... */
spin_lock_irq(&bp->lock);
@@ -1051,12 +1055,8 @@ static void bigmac_set_multicast(struct net_device *dev)
/* Ethtool support... */
static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct bigmac *bp = dev->priv;
-
strcpy(info->driver, "sunbmac");
strcpy(info->version, "2.0");
- sprintf(info->bus_info, "SBUS:%d",
- bp->qec_sdev->slot);
}
static u32 bigmac_get_link(struct net_device *dev)
@@ -1075,14 +1075,15 @@ static const struct ethtool_ops bigmac_ethtool_ops = {
.get_link = bigmac_get_link,
};
-static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
+static int __devinit bigmac_ether_init(struct of_device *op,
+ struct of_device *qec_op)
{
- struct net_device *dev;
static int version_printed;
- struct bigmac *bp;
+ struct net_device *dev;
u8 bsizes, bsizes_more;
- int i;
DECLARE_MAC_BUF(mac);
+ struct bigmac *bp;
+ int i;
/* Get a new device struct for this interface. */
dev = alloc_etherdev(sizeof(struct bigmac));
@@ -1092,32 +1093,21 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
- dev->base_addr = (long) qec_sdev;
for (i = 0; i < 6; i++)
dev->dev_addr[i] = idprom->id_ethaddr[i];
/* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */
- bp = dev->priv;
- bp->qec_sdev = qec_sdev;
- bp->bigmac_sdev = qec_sdev->child;
+ bp = netdev_priv(dev);
+ bp->qec_op = qec_op;
+ bp->bigmac_op = op;
- SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
spin_lock_init(&bp->lock);
- /* Verify the registers we expect, are actually there. */
- if ((bp->bigmac_sdev->num_registers != 3) ||
- (bp->qec_sdev->num_registers != 2)) {
- printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
- bp->qec_sdev->num_registers,
- bp->bigmac_sdev->num_registers);
- printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n");
- goto fail_and_cleanup;
- }
-
/* Map in QEC global control registers. */
- bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0,
- GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
+ bp->gregs = of_ioremap(&qec_op->resource[0], 0,
+ GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
if (!bp->gregs) {
printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n");
goto fail_and_cleanup;
@@ -1134,13 +1124,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
goto fail_and_cleanup;
/* Get supported SBUS burst sizes. */
- bsizes = prom_getintdefault(bp->qec_sdev->prom_node,
- "burst-sizes",
- 0xff);
-
- bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node,
- "burst-sizes",
- 0xff);
+ bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
+ bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
bsizes &= 0xff;
if (bsizes_more != 0xff)
@@ -1154,16 +1139,16 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
qec_init(bp);
/* Map in the BigMAC channel registers. */
- bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0,
- CREG_REG_SIZE, "BigMAC QEC Channel Regs");
+ bp->creg = of_ioremap(&op->resource[0], 0,
+ CREG_REG_SIZE, "BigMAC QEC Channel Regs");
if (!bp->creg) {
printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n");
goto fail_and_cleanup;
}
/* Map in the BigMAC control registers. */
- bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0,
- BMAC_REG_SIZE, "BigMAC Primary Regs");
+ bp->bregs = of_ioremap(&op->resource[1], 0,
+ BMAC_REG_SIZE, "BigMAC Primary Regs");
if (!bp->bregs) {
printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n");
goto fail_and_cleanup;
@@ -1172,8 +1157,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
/* Map in the BigMAC transceiver registers, this is how you poke at
* the BigMAC's PHY.
*/
- bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0,
- TCVR_REG_SIZE, "BigMAC Transceiver Regs");
+ bp->tregs = of_ioremap(&op->resource[2], 0,
+ TCVR_REG_SIZE, "BigMAC Transceiver Regs");
if (!bp->tregs) {
printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n");
goto fail_and_cleanup;
@@ -1183,17 +1168,17 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
bigmac_stop(bp);
/* Allocate transmit/receive descriptor DVMA block. */
- bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev,
- PAGE_SIZE,
- &bp->bblock_dvma);
+ bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev,
+ PAGE_SIZE,
+ &bp->bblock_dvma, GFP_ATOMIC);
if (bp->bmac_block == NULL || bp->bblock_dvma == 0) {
printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n");
goto fail_and_cleanup;
}
/* Get the board revision of this BigMAC. */
- bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node,
- "board-version", 1);
+ bp->board_rev = of_getintprop_default(bp->bigmac_op->node,
+ "board-version", 1);
/* Init auto-negotiation timer state. */
init_timer(&bp->bigmac_timer);
@@ -1217,7 +1202,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
dev->watchdog_timeo = 5*HZ;
/* Finish net device registration. */
- dev->irq = bp->bigmac_sdev->irqs[0];
+ dev->irq = bp->bigmac_op->irqs[0];
dev->dma = 0;
if (register_netdev(dev)) {
@@ -1225,7 +1210,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
goto fail_and_cleanup;
}
- dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
+ dev_set_drvdata(&bp->bigmac_op->dev, bp);
printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
dev->name, print_mac(mac, dev->dev_addr));
@@ -1236,66 +1221,67 @@ fail_and_cleanup:
/* Something went wrong, undo whatever we did so far. */
/* Free register mappings if any. */
if (bp->gregs)
- sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
+ of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
if (bp->creg)
- sbus_iounmap(bp->creg, CREG_REG_SIZE);
+ of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
if (bp->bregs)
- sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
+ of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
if (bp->tregs)
- sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
+ of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
if (bp->bmac_block)
- sbus_free_consistent(bp->bigmac_sdev,
- PAGE_SIZE,
- bp->bmac_block,
- bp->bblock_dvma);
+ dma_free_coherent(&bp->bigmac_op->dev,
+ PAGE_SIZE,
+ bp->bmac_block,
+ bp->bblock_dvma);
/* This also frees the co-located 'dev->priv' */
free_netdev(dev);
return -ENODEV;
}
-/* QEC can be the parent of either QuadEthernet or
- * a BigMAC. We want the latter.
+/* QEC can be the parent of either QuadEthernet or a BigMAC. We want
+ * the latter.
*/
-static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit bigmac_sbus_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
+ struct device *parent = op->dev.parent;
+ struct of_device *qec_op;
- if (!strcmp(dp->name, "be"))
- sdev = sdev->parent;
+ qec_op = to_of_device(parent);
- return bigmac_ether_init(sdev);
+ return bigmac_ether_init(op, qec_op);
}
-static int __devexit bigmac_sbus_remove(struct of_device *dev)
+static int __devexit bigmac_sbus_remove(struct of_device *op)
{
- struct bigmac *bp = dev_get_drvdata(&dev->dev);
+ struct bigmac *bp = dev_get_drvdata(&op->dev);
+ struct device *parent = op->dev.parent;
struct net_device *net_dev = bp->dev;
+ struct of_device *qec_op;
+
+ qec_op = to_of_device(parent);
unregister_netdev(net_dev);
- sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
- sbus_iounmap(bp->creg, CREG_REG_SIZE);
- sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
- sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
- sbus_free_consistent(bp->bigmac_sdev,
- PAGE_SIZE,
- bp->bmac_block,
- bp->bblock_dvma);
+ of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
+ of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
+ of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
+ of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
+ dma_free_coherent(&op->dev,
+ PAGE_SIZE,
+ bp->bmac_block,
+ bp->bblock_dvma);
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id bigmac_sbus_match[] = {
- {
- .name = "qec",
- },
+static const struct of_device_id bigmac_sbus_match[] = {
{
.name = "be",
},
@@ -1313,7 +1299,7 @@ static struct of_platform_driver bigmac_sbus_driver = {
static int __init bigmac_init(void)
{
- return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&bigmac_sbus_driver, &of_bus_type);
}
static void __exit bigmac_exit(void)
diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h
index b563d3c2993..8840bc0b840 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/sunbmac.h
@@ -329,8 +329,8 @@ struct bigmac {
unsigned int timer_ticks;
struct net_device_stats enet_stats;
- struct sbus_dev *qec_sdev;
- struct sbus_dev *bigmac_sdev;
+ struct of_device *qec_op;
+ struct of_device *bigmac_op;
struct net_device *dev;
};
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index b79d5f018f7..f1ebeb5f65b 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3,7 +3,7 @@
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
* Copyright (C) 1996, 1998, 1999, 2002, 2003,
- 2006 David S. Miller (davem@davemloft.net)
+ * 2006, 2008 David S. Miller (davem@davemloft.net)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -34,6 +34,7 @@
#include <linux/skbuff.h>
#include <linux/mm.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -41,8 +42,9 @@
#include <asm/byteorder.h>
#ifdef CONFIG_SPARC
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/prom.h>
@@ -60,8 +62,8 @@
#include "sunhme.h"
#define DRV_NAME "sunhme"
-#define DRV_VERSION "3.00"
-#define DRV_RELDATE "June 23, 2006"
+#define DRV_VERSION "3.10"
+#define DRV_RELDATE "August 26, 2008"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
@@ -251,13 +253,13 @@ static u32 pci_hme_read_desc32(hme32 *p)
#define hme_read_desc32(__hp, __p) \
((__hp)->read_desc32(__p))
#define hme_dma_map(__hp, __ptr, __size, __dir) \
- ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
+ ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir)))
#define hme_dma_unmap(__hp, __addr, __size, __dir) \
- ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
+ ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir)))
#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
- ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)))
+ ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)))
#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
- ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)))
+ ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)))
#else
#ifdef CONFIG_SBUS
/* SBUS only compilation */
@@ -277,13 +279,13 @@ do { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \
} while(0)
#define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p))
#define hme_dma_map(__hp, __ptr, __size, __dir) \
- sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+ dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
#define hme_dma_unmap(__hp, __addr, __size, __dir) \
- sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+ dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
- sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+ dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
- sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+ dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
#else
/* PCI only compilation */
#define hme_write32(__hp, __reg, __val) \
@@ -305,36 +307,17 @@ static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p)
return le32_to_cpup((__le32 *)p);
}
#define hme_dma_map(__hp, __ptr, __size, __dir) \
- pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+ pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
#define hme_dma_unmap(__hp, __addr, __size, __dir) \
- pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+ pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
- pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+ pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
- pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+ pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
#endif
#endif
-#ifdef SBUS_DMA_BIDIRECTIONAL
-# define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL
-#else
-# define DMA_BIDIRECTIONAL 0
-#endif
-
-#ifdef SBUS_DMA_FROMDEVICE
-# define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE
-#else
-# define DMA_TODEVICE 1
-#endif
-
-#ifdef SBUS_DMA_TODEVICE
-# define DMA_TODEVICE SBUS_DMA_TODEVICE
-#else
-# define DMA_FROMDEVICE 2
-#endif
-
-
/* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */
static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit)
{
@@ -1224,7 +1207,8 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
rxd = &hp->happy_block->happy_meal_rxd[i];
dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
- hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr,
+ RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
hp->rx_skbs[i] = NULL;
}
@@ -1242,10 +1226,10 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
txd = &hp->happy_block->happy_meal_txd[i];
dma_addr = hme_read_desc32(hp, &txd->tx_addr);
- hme_dma_unmap(hp, dma_addr,
- (hme_read_desc32(hp, &txd->tx_flags)
- & TXFLAG_SIZE),
- DMA_TODEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr,
+ (hme_read_desc32(hp, &txd->tx_flags)
+ & TXFLAG_SIZE),
+ DMA_TO_DEVICE);
if (frag != skb_shinfo(skb)->nr_frags)
i++;
@@ -1287,7 +1271,8 @@ static void happy_meal_init_rings(struct happy_meal *hp)
skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
hme_write_rxd(hp, &hb->happy_meal_rxd[i],
(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),
- hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+ dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE,
+ DMA_FROM_DEVICE));
skb_reserve(skb, RX_OFFSET);
}
@@ -1593,7 +1578,7 @@ static int happy_meal_init(struct happy_meal *hp)
if ((hp->happy_bursts & DMA_BURST64) &&
((hp->happy_flags & HFLAG_PCI) != 0
#ifdef CONFIG_SBUS
- || sbus_can_burst64(hp->happy_dev)
+ || sbus_can_burst64()
#endif
|| 0)) {
u32 gcfg = GREG_CFG_BURST64;
@@ -1603,11 +1588,13 @@ static int happy_meal_init(struct happy_meal *hp)
* do not. -DaveM
*/
#ifdef CONFIG_SBUS
- if ((hp->happy_flags & HFLAG_PCI) == 0 &&
- sbus_can_dma_64bit(hp->happy_dev)) {
- sbus_set_sbus64(hp->happy_dev,
- hp->happy_bursts);
- gcfg |= GREG_CFG_64BIT;
+ if ((hp->happy_flags & HFLAG_PCI) == 0) {
+ struct of_device *op = hp->happy_dev;
+ if (sbus_can_dma_64bit()) {
+ sbus_set_sbus64(&op->dev,
+ hp->happy_bursts);
+ gcfg |= GREG_CFG_64BIT;
+ }
}
#endif
@@ -1966,7 +1953,7 @@ static void happy_meal_tx(struct happy_meal *hp)
dma_len = hme_read_desc32(hp, &this->tx_flags);
dma_len &= TXFLAG_SIZE;
- hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE);
elem = NEXT_TX(elem);
this = &txbase[elem];
@@ -2044,13 +2031,14 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
drops++;
goto drop_it;
}
- hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+ dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
hp->rx_skbs[elem] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
hme_write_rxd(hp, this,
(RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
- hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+ dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE,
+ DMA_FROM_DEVICE));
skb_reserve(new_skb, RX_OFFSET);
/* Trim the original skb for the netif. */
@@ -2065,10 +2053,9 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
- hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
skb_copy_from_linear_data(skb, copy_skb->data, len);
- hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);
-
+ dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
/* Reuse original ring buffer. */
hme_write_rxd(hp, this,
(RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
@@ -2300,7 +2287,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 mapping, len;
len = skb->len;
- mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
+ mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE);
tx_flags |= (TXFLAG_SOP | TXFLAG_EOP);
hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
(tx_flags | (len & TXFLAG_SIZE)),
@@ -2314,7 +2301,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
* Otherwise we could race with the device.
*/
first_len = skb_headlen(skb);
- first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE);
+ first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len,
+ DMA_TO_DEVICE);
entry = NEXT_TX(entry);
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -2322,10 +2310,9 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 len, mapping, this_txflags;
len = this_frag->size;
- mapping = hme_dma_map(hp,
- ((void *) page_address(this_frag->page) +
- this_frag->page_offset),
- len, DMA_TODEVICE);
+ mapping = dma_map_page(hp->dma_dev, this_frag->page,
+ this_frag->page_offset, len,
+ DMA_TO_DEVICE);
this_txflags = tx_flags;
if (frag == skb_shinfo(skb)->nr_frags - 1)
this_txflags |= TXFLAG_EOP;
@@ -2493,9 +2480,12 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
}
#ifdef CONFIG_SBUS
else {
- struct sbus_dev *sdev = hp->happy_dev;
- sprintf(info->bus_info, "SBUS:%d",
- sdev->slot);
+ const struct linux_prom_registers *regs;
+ struct of_device *op = hp->happy_dev;
+ regs = of_get_property(op->node, "regs", NULL);
+ if (regs)
+ sprintf(info->bus_info, "SBUS:%d",
+ regs->which_io);
}
#endif
}
@@ -2521,63 +2511,21 @@ static const struct ethtool_ops hme_ethtool_ops = {
static int hme_version_printed;
#ifdef CONFIG_SBUS
-void __devinit quattro_get_ranges(struct quattro *qp)
-{
- struct sbus_dev *sdev = qp->quattro_dev;
- int err;
-
- err = prom_getproperty(sdev->prom_node,
- "ranges",
- (char *)&qp->ranges[0],
- sizeof(qp->ranges));
- if (err == 0 || err == -1) {
- qp->nranges = 0;
- return;
- }
- qp->nranges = (err / sizeof(struct linux_prom_ranges));
-}
-
-static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
-{
- struct sbus_dev *sdev = hp->happy_dev;
- int rng;
-
- for (rng = 0; rng < qp->nranges; rng++) {
- struct linux_prom_ranges *rngp = &qp->ranges[rng];
- int reg;
-
- for (reg = 0; reg < 5; reg++) {
- if (sdev->reg_addrs[reg].which_io ==
- rngp->ot_child_space)
- break;
- }
- if (reg == 5)
- continue;
-
- sdev->reg_addrs[reg].which_io = rngp->ot_parent_space;
- sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base;
- }
-}
-
/* Given a happy meal sbus device, find it's quattro parent.
* If none exist, allocate and return a new one.
*
* Return NULL on failure.
*/
-static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
+static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
{
- struct sbus_dev *sdev;
+ struct device *parent = child->dev.parent;
+ struct of_device *op;
struct quattro *qp;
- int i;
- for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
- for (i = 0, sdev = qp->quattro_dev;
- (sdev != NULL) && (i < 4);
- sdev = sdev->next, i++) {
- if (sdev == goal_sdev)
- return qp;
- }
- }
+ op = to_of_device(parent);
+ qp = dev_get_drvdata(&op->dev);
+ if (qp)
+ return qp;
qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
if (qp != NULL) {
@@ -2586,10 +2534,11 @@ static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
for (i = 0; i < 4; i++)
qp->happy_meals[i] = NULL;
- qp->quattro_dev = goal_sdev;
+ qp->quattro_dev = child;
qp->next = qfe_sbus_list;
qfe_sbus_list = qp;
- quattro_get_ranges(qp);
+
+ dev_set_drvdata(&op->dev, qp);
}
return qp;
}
@@ -2602,10 +2551,10 @@ static void __init quattro_sbus_register_irqs(void)
struct quattro *qp;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
- struct sbus_dev *sdev = qp->quattro_dev;
+ struct of_device *op = qp->quattro_dev;
int err;
- err = request_irq(sdev->irqs[0],
+ err = request_irq(op->irqs[0],
quattro_sbus_interrupt,
IRQF_SHARED, "Quattro",
qp);
@@ -2621,9 +2570,9 @@ static void quattro_sbus_free_irqs(void)
struct quattro *qp;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
- struct sbus_dev *sdev = qp->quattro_dev;
+ struct of_device *op = qp->quattro_dev;
- free_irq(sdev->irqs[0], qp);
+ free_irq(op->irqs[0], qp);
}
}
#endif /* CONFIG_SBUS */
@@ -2660,9 +2609,9 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
-static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
+static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
{
- struct device_node *dp = sdev->ofdev.node;
+ struct device_node *dp = op->node, *sbus_dp;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
@@ -2671,7 +2620,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
DECLARE_MAC_BUF(mac);
if (is_qfe) {
- qp = quattro_sbus_find(sdev);
+ qp = quattro_sbus_find(op);
if (qp == NULL)
goto err_out;
for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
@@ -2685,7 +2634,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
dev = alloc_etherdev(sizeof(struct happy_meal));
if (!dev)
goto err_out;
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -2713,56 +2662,50 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
- hp = dev->priv;
+ hp = netdev_priv(dev);
- hp->happy_dev = sdev;
+ hp->happy_dev = op;
+ hp->dma_dev = &op->dev;
spin_lock_init(&hp->happy_lock);
err = -ENODEV;
- if (sdev->num_registers != 5) {
- printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
- sdev->num_registers);
- goto err_out_free_netdev;
- }
-
if (qp != NULL) {
hp->qfe_parent = qp;
hp->qfe_ent = qfe_slot;
qp->happy_meals[qfe_slot] = dev;
- quattro_apply_ranges(qp, hp);
}
- hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
- GREG_REG_SIZE, "HME Global Regs");
+ hp->gregs = of_ioremap(&op->resource[0], 0,
+ GREG_REG_SIZE, "HME Global Regs");
if (!hp->gregs) {
printk(KERN_ERR "happymeal: Cannot map global registers.\n");
goto err_out_free_netdev;
}
- hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
- ETX_REG_SIZE, "HME TX Regs");
+ hp->etxregs = of_ioremap(&op->resource[1], 0,
+ ETX_REG_SIZE, "HME TX Regs");
if (!hp->etxregs) {
printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
goto err_out_iounmap;
}
- hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
- ERX_REG_SIZE, "HME RX Regs");
+ hp->erxregs = of_ioremap(&op->resource[2], 0,
+ ERX_REG_SIZE, "HME RX Regs");
if (!hp->erxregs) {
printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
goto err_out_iounmap;
}
- hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
- BMAC_REG_SIZE, "HME BIGMAC Regs");
+ hp->bigmacregs = of_ioremap(&op->resource[3], 0,
+ BMAC_REG_SIZE, "HME BIGMAC Regs");
if (!hp->bigmacregs) {
printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
goto err_out_iounmap;
}
- hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
- TCVR_REG_SIZE, "HME Tranceiver Regs");
+ hp->tcvregs = of_ioremap(&op->resource[4], 0,
+ TCVR_REG_SIZE, "HME Tranceiver Regs");
if (!hp->tcvregs) {
printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
goto err_out_iounmap;
@@ -2781,13 +2724,18 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
if (qp != NULL)
hp->happy_flags |= HFLAG_QUATTRO;
+ sbus_dp = to_of_device(op->dev.parent)->node;
+ if (is_qfe)
+ sbus_dp = to_of_device(op->dev.parent->parent)->node;
+
/* Get the supported DVMA burst sizes from our Happy SBUS. */
- hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
+ hp->happy_bursts = of_getintprop_default(sbus_dp,
"burst-sizes", 0x00);
- hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
- PAGE_SIZE,
- &hp->hblock_dvma);
+ hp->happy_block = dma_alloc_coherent(hp->dma_dev,
+ PAGE_SIZE,
+ &hp->hblock_dvma,
+ GFP_ATOMIC);
err = -ENOMEM;
if (!hp->happy_block) {
printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n");
@@ -2816,19 +2764,13 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
/* Happy Meal can do it all... */
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->irq = sdev->irqs[0];
+ dev->irq = op->irqs[0];
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
- /* Hook up PCI register/dma accessors. */
+ /* Hook up SBUS register/descriptor accessors. */
hp->read_desc32 = sbus_hme_read_desc32;
hp->write_txd = sbus_hme_write_txd;
hp->write_rxd = sbus_hme_write_rxd;
- hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single;
- hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single;
- hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
- sbus_dma_sync_single_for_cpu;
- hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
- sbus_dma_sync_single_for_device;
hp->read32 = sbus_hme_read32;
hp->write32 = sbus_hme_write32;
#endif
@@ -2843,10 +2785,10 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
if (register_netdev(hp->dev)) {
printk(KERN_ERR "happymeal: Cannot register net device, "
"aborting.\n");
- goto err_out_free_consistent;
+ goto err_out_free_coherent;
}
- dev_set_drvdata(&sdev->ofdev.dev, hp);
+ dev_set_drvdata(&op->dev, hp);
if (qfe_slot != -1)
printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
@@ -2859,23 +2801,23 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
return 0;
-err_out_free_consistent:
- sbus_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
+err_out_free_coherent:
+ dma_free_coherent(hp->dma_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
err_out_iounmap:
if (hp->gregs)
- sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+ of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
if (hp->etxregs)
- sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+ of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
if (hp->erxregs)
- sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+ of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
if (hp->bigmacregs)
- sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+ of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
if (hp->tcvregs)
- sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+ of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
err_out_free_netdev:
free_netdev(dev);
@@ -3035,6 +2977,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
memset(hp, 0, sizeof(*hp));
hp->happy_dev = pdev;
+ hp->dma_dev = &pdev->dev;
spin_lock_init(&hp->happy_lock);
@@ -3121,7 +3064,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
#endif
hp->happy_block = (struct hmeal_init_block *)
- pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma);
+ dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL);
err = -ENODEV;
if (!hp->happy_block) {
@@ -3151,16 +3094,10 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
- /* Hook up PCI register/dma accessors. */
+ /* Hook up PCI register/descriptor accessors. */
hp->read_desc32 = pci_hme_read_desc32;
hp->write_txd = pci_hme_write_txd;
hp->write_rxd = pci_hme_write_rxd;
- hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single;
- hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single;
- hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
- pci_dma_sync_single_for_cpu;
- hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
- pci_dma_sync_single_for_device;
hp->read32 = pci_hme_read32;
hp->write32 = pci_hme_write32;
#endif
@@ -3231,10 +3168,8 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
unregister_netdev(net_dev);
- pci_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
+ dma_free_coherent(hp->dma_dev, PAGE_SIZE,
+ hp->happy_block, hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
@@ -3279,46 +3214,45 @@ static void happy_meal_pci_exit(void)
#endif
#ifdef CONFIG_SBUS
-static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
+ struct device_node *dp = op->node;
const char *model = of_get_property(dp, "model", NULL);
int is_qfe = (match->data != NULL);
if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
is_qfe = 1;
- return happy_meal_sbus_probe_one(sdev, is_qfe);
+ return happy_meal_sbus_probe_one(op, is_qfe);
}
-static int __devexit hme_sbus_remove(struct of_device *dev)
+static int __devexit hme_sbus_remove(struct of_device *op)
{
- struct happy_meal *hp = dev_get_drvdata(&dev->dev);
+ struct happy_meal *hp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = hp->dev;
unregister_netdev(net_dev);
/* XXX qfe parent interrupt... */
- sbus_iounmap(hp->gregs, GREG_REG_SIZE);
- sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
- sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
- sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
- sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
- sbus_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
+ of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
+ of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
+ of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
+ of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
+ of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
+ dma_free_coherent(hp->dma_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id hme_sbus_match[] = {
+static const struct of_device_id hme_sbus_match[] = {
{
.name = "SUNW,hme",
},
@@ -3346,7 +3280,7 @@ static int __init happy_meal_sbus_init(void)
{
int err;
- err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+ err = of_register_driver(&hme_sbus_driver, &of_bus_type);
if (!err)
quattro_sbus_register_irqs();
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 4da5539fac7..efd2ca0fcad 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -405,14 +405,11 @@ struct happy_meal {
u32 (*read_desc32)(hme32 *);
void (*write_txd)(struct happy_meal_txd *, u32, u32);
void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
- u32 (*dma_map)(void *, void *, long, int);
- void (*dma_unmap)(void *, u32, long, int);
- void (*dma_sync_for_cpu)(void *, u32, long, int);
- void (*dma_sync_for_device)(void *, u32, long, int);
#endif
- /* This is either a sbus_dev or a pci_dev. */
+ /* This is either an of_device or a pci_dev. */
void *happy_dev;
+ struct device *dma_dev;
spinlock_t happy_lock;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 4e994f87469..704301a5a7f 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -91,6 +91,9 @@ static char lancestr[] = "LANCE";
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -98,7 +101,6 @@ static char lancestr[] = "LANCE";
#include <asm/pgtable.h>
#include <asm/byteorder.h> /* Used by the checksum routines */
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/prom.h>
#include <asm/auxio.h> /* For tpe-link-test? setting */
#include <asm/irq.h>
@@ -248,7 +250,7 @@ struct lance_private {
int rx_new, tx_new;
int rx_old, tx_old;
- struct sbus_dma *ledma; /* If set this points to ledma */
+ struct of_device *ledma; /* If set this points to ledma */
char tpe; /* cable-selection is TPE */
char auto_select; /* cable-selection by carrier */
char burst_sizes; /* ledma SBus burst sizes */
@@ -263,7 +265,8 @@ struct lance_private {
char *name;
dma_addr_t init_block_dvma;
struct net_device *dev; /* Backpointer */
- struct sbus_dev *sdev;
+ struct of_device *op;
+ struct of_device *lebuffer;
struct timer_list multicast_timer;
};
@@ -1272,27 +1275,29 @@ static void lance_set_multicast_retry(unsigned long _opaque)
static void lance_free_hwresources(struct lance_private *lp)
{
if (lp->lregs)
- sbus_iounmap(lp->lregs, LANCE_REG_SIZE);
+ of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE);
+ if (lp->dregs) {
+ struct of_device *ledma = lp->ledma;
+
+ of_iounmap(&ledma->resource[0], lp->dregs,
+ resource_size(&ledma->resource[0]));
+ }
if (lp->init_block_iomem) {
- sbus_iounmap(lp->init_block_iomem,
- sizeof(struct lance_init_block));
+ of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem,
+ sizeof(struct lance_init_block));
} else if (lp->init_block_mem) {
- sbus_free_consistent(lp->sdev,
- sizeof(struct lance_init_block),
- lp->init_block_mem,
- lp->init_block_dvma);
+ dma_free_coherent(&lp->op->dev,
+ sizeof(struct lance_init_block),
+ lp->init_block_mem,
+ lp->init_block_dvma);
}
}
/* Ethtool support... */
static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct lance_private *lp = netdev_priv(dev);
-
strcpy(info->driver, "sunlance");
strcpy(info->version, "2.02");
- sprintf(info->bus_info, "SBUS:%d",
- lp->sdev->slot);
}
static u32 sparc_lance_get_link(struct net_device *dev)
@@ -1308,16 +1313,16 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = {
.get_link = sparc_lance_get_link,
};
-static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
- struct sbus_dma *ledma,
- struct sbus_dev *lebuffer)
+static int __devinit sparc_lance_probe_one(struct of_device *op,
+ struct of_device *ledma,
+ struct of_device *lebuffer)
{
+ struct device_node *dp = op->node;
static unsigned version_printed;
- struct device_node *dp = sdev->ofdev.node;
- struct net_device *dev;
struct lance_private *lp;
- int i;
+ struct net_device *dev;
DECLARE_MAC_BUF(mac);
+ int i;
dev = alloc_etherdev(sizeof(struct lance_private) + 8);
if (!dev)
@@ -1338,14 +1343,27 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
dev->dev_addr[i] = idprom->id_ethaddr[i];
/* Get the IO region */
- lp->lregs = sbus_ioremap(&sdev->resource[0], 0,
- LANCE_REG_SIZE, lancestr);
+ lp->lregs = of_ioremap(&op->resource[0], 0,
+ LANCE_REG_SIZE, lancestr);
if (!lp->lregs) {
printk(KERN_ERR "SunLance: Cannot map registers.\n");
goto fail;
}
- lp->sdev = sdev;
+ lp->ledma = ledma;
+ if (lp->ledma) {
+ lp->dregs = of_ioremap(&ledma->resource[0], 0,
+ resource_size(&ledma->resource[0]),
+ "ledma");
+ if (!lp->dregs) {
+ printk(KERN_ERR "SunLance: Cannot map "
+ "ledma registers.\n");
+ goto fail;
+ }
+ }
+
+ lp->op = op;
+ lp->lebuffer = lebuffer;
if (lebuffer) {
/* sanity check */
if (lebuffer->resource[0].start & 7) {
@@ -1353,8 +1371,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
goto fail;
}
lp->init_block_iomem =
- sbus_ioremap(&lebuffer->resource[0], 0,
- sizeof(struct lance_init_block), "lebuffer");
+ of_ioremap(&lebuffer->resource[0], 0,
+ sizeof(struct lance_init_block), "lebuffer");
if (!lp->init_block_iomem) {
printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n");
goto fail;
@@ -1366,9 +1384,10 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
lp->tx = lance_tx_pio;
} else {
lp->init_block_mem =
- sbus_alloc_consistent(sdev, sizeof(struct lance_init_block),
- &lp->init_block_dvma);
- if (!lp->init_block_mem || lp->init_block_dvma == 0) {
+ dma_alloc_coherent(&op->dev,
+ sizeof(struct lance_init_block),
+ &lp->init_block_dvma, GFP_ATOMIC);
+ if (!lp->init_block_mem) {
printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n");
goto fail;
}
@@ -1383,13 +1402,13 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
LE_C3_BCON));
lp->name = lancestr;
- lp->ledma = ledma;
lp->burst_sizes = 0;
if (lp->ledma) {
- struct device_node *ledma_dp = ledma->sdev->ofdev.node;
- const char *prop;
+ struct device_node *ledma_dp = ledma->node;
+ struct device_node *sbus_dp;
unsigned int sbmask;
+ const char *prop;
u32 csr;
/* Find burst-size property for ledma */
@@ -1397,7 +1416,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
"burst-sizes", 0);
/* ledma may be capable of fast bursts, but sbus may not. */
- sbmask = of_getintprop_default(ledma_dp, "burst-sizes",
+ sbus_dp = ledma_dp->parent;
+ sbmask = of_getintprop_default(sbus_dp, "burst-sizes",
DMA_BURSTBITS);
lp->burst_sizes &= sbmask;
@@ -1435,8 +1455,6 @@ no_link_test:
lp->tpe = 1;
}
- lp->dregs = ledma->regs;
-
/* Reset ledma */
csr = sbus_readl(lp->dregs + DMA_CSR);
sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR);
@@ -1446,7 +1464,7 @@ no_link_test:
lp->dregs = NULL;
lp->dev = dev;
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
@@ -1455,9 +1473,7 @@ no_link_test:
dev->set_multicast_list = &lance_set_multicast;
dev->ethtool_ops = &sparc_lance_ethtool_ops;
- dev->irq = sdev->irqs[0];
-
- dev->dma = 0;
+ dev->irq = op->irqs[0];
/* We cannot sleep if the chip is busy during a
* multicast list update event, because such events
@@ -1473,7 +1489,7 @@ no_link_test:
goto fail;
}
- dev_set_drvdata(&sdev->ofdev.dev, lp);
+ dev_set_drvdata(&op->dev, lp);
printk(KERN_INFO "%s: LANCE %s\n",
dev->name, print_mac(mac, dev->dev_addr));
@@ -1486,80 +1502,25 @@ fail:
return -ENODEV;
}
-/* On 4m, find the associated dma for the lance chip */
-static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
-{
- struct sbus_dma *p;
-
- for_each_dvma(p) {
- if (p->sdev == sdev)
- return p;
- }
- return NULL;
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-/* Find all the lance cards on the system and initialize them */
-static struct sbus_dev sun4_sdev;
-static int __devinit sparc_lance_init(void)
-{
- if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
- (idprom->id_machtype == (SM_SUN4|SM_4_470))) {
- memset(&sun4_sdev, 0, sizeof(struct sbus_dev));
- sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
- sun4_sdev.irqs[0] = 6;
- return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
- }
- return -ENODEV;
-}
-
-static int __exit sunlance_sun4_remove(void)
+static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev);
- struct net_device *net_dev = lp->dev;
-
- unregister_netdev(net_dev);
-
- lance_free_hwresources(lp);
-
- free_netdev(net_dev);
-
- dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL);
-
- return 0;
-}
-
-#else /* !CONFIG_SUN4 */
-
-static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct of_device *parent = to_of_device(op->dev.parent);
+ struct device_node *parent_dp = parent->node;
int err;
- if (sdev->parent) {
- struct of_device *parent = &sdev->parent->ofdev;
-
- if (!strcmp(parent->node->name, "ledma")) {
- struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev));
-
- err = sparc_lance_probe_one(sdev, ledma, NULL);
- } else if (!strcmp(parent->node->name, "lebuffer")) {
- err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev));
- } else
- err = sparc_lance_probe_one(sdev, NULL, NULL);
+ if (!strcmp(parent_dp->name, "ledma")) {
+ err = sparc_lance_probe_one(op, parent, NULL);
+ } else if (!strcmp(parent_dp->name, "lebuffer")) {
+ err = sparc_lance_probe_one(op, NULL, parent);
} else
- err = sparc_lance_probe_one(sdev, NULL, NULL);
+ err = sparc_lance_probe_one(op, NULL, NULL);
return err;
}
-static int __devexit sunlance_sbus_remove(struct of_device *dev)
+static int __devexit sunlance_sbus_remove(struct of_device *op)
{
- struct lance_private *lp = dev_get_drvdata(&dev->dev);
+ struct lance_private *lp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = lp->dev;
unregister_netdev(net_dev);
@@ -1568,12 +1529,12 @@ static int __devexit sunlance_sbus_remove(struct of_device *dev)
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id sunlance_sbus_match[] = {
+static const struct of_device_id sunlance_sbus_match[] = {
{
.name = "le",
},
@@ -1593,17 +1554,12 @@ static struct of_platform_driver sunlance_sbus_driver = {
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_init(void)
{
- return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&sunlance_sbus_driver, &of_bus_type);
}
-#endif /* !CONFIG_SUN4 */
static void __exit sparc_lance_exit(void)
{
-#ifdef CONFIG_SUN4
- sunlance_sun4_remove();
-#else
of_unregister_driver(&sunlance_sbus_driver);
-#endif
}
module_init(sparc_lance_init);
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index e811331d460..f63644744ff 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -3,7 +3,7 @@
* controller out there can be most efficiently programmed
* if you make it look like a LANCE.
*
- * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -24,13 +24,15 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/idprom.h>
-#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/auxio.h>
@@ -40,8 +42,8 @@
#include "sunqe.h"
#define DRV_NAME "sunqe"
-#define DRV_VERSION "4.0"
-#define DRV_RELDATE "June 23, 2006"
+#define DRV_VERSION "4.1"
+#define DRV_RELDATE "August 27, 2008"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
@@ -690,12 +692,18 @@ static void qe_set_multicast(struct net_device *dev)
/* Ethtool support... */
static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
+ const struct linux_prom_registers *regs;
struct sunqe *qep = dev->priv;
+ struct of_device *op;
strcpy(info->driver, "sunqe");
strcpy(info->version, "3.0");
- sprintf(info->bus_info, "SBUS:%d",
- qep->qe_sdev->slot);
+
+ op = qep->op;
+ regs = of_get_property(op->node, "reg", NULL);
+ if (regs)
+ sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+
}
static u32 qe_get_link(struct net_device *dev)
@@ -717,11 +725,11 @@ static const struct ethtool_ops qe_ethtool_ops = {
};
/* This is only called once at boot time for each card probed. */
-static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
+static void qec_init_once(struct sunqec *qecp, struct of_device *op)
{
u8 bsizes = qecp->qec_bursts;
- if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) {
+ if (sbus_can_burst64() && (bsizes & DMA_BURST64)) {
sbus_writel(GLOB_CTRL_B64, qecp->gregs + GLOB_CTRL);
} else if (bsizes & DMA_BURST32) {
sbus_writel(GLOB_CTRL_B32, qecp->gregs + GLOB_CTRL);
@@ -735,15 +743,15 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE);
/* Set the local memsize register, divided up to one piece per QE channel. */
- sbus_writel((qsdev->reg_addrs[1].reg_size >> 2),
+ sbus_writel((resource_size(&op->resource[1]) >> 2),
qecp->gregs + GLOB_MSIZE);
/* Divide up the local QEC memory amongst the 4 QE receiver and
* transmitter FIFOs. Basically it is (total / 2 / num_channels).
*/
- sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+ sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
qecp->gregs + GLOB_TSIZE);
- sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+ sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
qecp->gregs + GLOB_RSIZE);
}
@@ -767,24 +775,21 @@ static u8 __devinit qec_get_burst(struct device_node *dp)
return bsizes;
}
-static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
+static struct sunqec * __devinit get_qec(struct of_device *child)
{
- struct sbus_dev *qec_sdev = child_sdev->parent;
+ struct of_device *op = to_of_device(child->dev.parent);
struct sunqec *qecp;
- for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
- if (qecp->qec_sdev == qec_sdev)
- break;
- }
+ qecp = dev_get_drvdata(&op->dev);
if (!qecp) {
qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
if (qecp) {
u32 ctrl;
- qecp->qec_sdev = qec_sdev;
- qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
- GLOB_REG_SIZE,
- "QEC Global Registers");
+ qecp->op = op;
+ qecp->gregs = of_ioremap(&op->resource[0], 0,
+ GLOB_REG_SIZE,
+ "QEC Global Registers");
if (!qecp->gregs)
goto fail;
@@ -799,16 +804,18 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
if (qec_global_reset(qecp->gregs))
goto fail;
- qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
+ qecp->qec_bursts = qec_get_burst(op->node);
- qec_init_once(qecp, qec_sdev);
+ qec_init_once(qecp, op);
- if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
+ if (request_irq(op->irqs[0], &qec_interrupt,
IRQF_SHARED, "qec", (void *) qecp)) {
printk(KERN_ERR "qec: Can't register irq.\n");
goto fail;
}
+ dev_set_drvdata(&op->dev, qecp);
+
qecp->next_module = root_qec_dev;
root_qec_dev = qecp;
}
@@ -818,17 +825,17 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
fail:
if (qecp->gregs)
- sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
+ of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE);
kfree(qecp);
return NULL;
}
-static int __devinit qec_ether_init(struct sbus_dev *sdev)
+static int __devinit qec_ether_init(struct of_device *op)
{
static unsigned version_printed;
struct net_device *dev;
- struct sunqe *qe;
struct sunqec *qecp;
+ struct sunqe *qe;
int i, res;
if (version_printed++ == 0)
@@ -842,49 +849,42 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
qe = netdev_priv(dev);
- i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
- if (i == -1) {
- struct sbus_dev *td = sdev->parent->child;
- i = 0;
- while (td != sdev) {
- td = td->next;
- i++;
- }
- }
+ res = -ENODEV;
+
+ i = of_getintprop_default(op->node, "channel#", -1);
+ if (i == -1)
+ goto fail;
qe->channel = i;
spin_lock_init(&qe->lock);
- res = -ENODEV;
- qecp = get_qec(sdev);
+ qecp = get_qec(op);
if (!qecp)
goto fail;
qecp->qes[qe->channel] = qe;
qe->dev = dev;
qe->parent = qecp;
- qe->qe_sdev = sdev;
+ qe->op = op;
res = -ENOMEM;
- qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
- CREG_REG_SIZE, "QEC Channel Registers");
+ qe->qcregs = of_ioremap(&op->resource[0], 0,
+ CREG_REG_SIZE, "QEC Channel Registers");
if (!qe->qcregs) {
printk(KERN_ERR "qe: Cannot map channel registers.\n");
goto fail;
}
- qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
- MREGS_REG_SIZE, "QE MACE Registers");
+ qe->mregs = of_ioremap(&op->resource[1], 0,
+ MREGS_REG_SIZE, "QE MACE Registers");
if (!qe->mregs) {
printk(KERN_ERR "qe: Cannot map MACE registers.\n");
goto fail;
}
- qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
- PAGE_SIZE,
- &qe->qblock_dvma);
- qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
- sizeof(struct sunqe_buffers),
- &qe->buffers_dvma);
+ qe->qe_block = dma_alloc_coherent(&op->dev, PAGE_SIZE,
+ &qe->qblock_dvma, GFP_ATOMIC);
+ qe->buffers = dma_alloc_coherent(&op->dev, sizeof(struct sunqe_buffers),
+ &qe->buffers_dvma, GFP_ATOMIC);
if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
qe->buffers == NULL || qe->buffers_dvma == 0)
goto fail;
@@ -892,7 +892,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
/* Stop this QE. */
qe_stop(qe);
- SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+ SET_NETDEV_DEV(dev, &op->dev);
dev->open = qe_open;
dev->stop = qe_close;
@@ -900,7 +900,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
dev->set_multicast_list = qe_set_multicast;
dev->tx_timeout = qe_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->irq = sdev->irqs[0];
+ dev->irq = op->irqs[0];
dev->dma = 0;
dev->ethtool_ops = &qe_ethtool_ops;
@@ -908,7 +908,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
if (res)
goto fail;
- dev_set_drvdata(&sdev->ofdev.dev, qe);
+ dev_set_drvdata(&op->dev, qe);
printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
for (i = 0; i < 6; i++)
@@ -922,58 +922,50 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
fail:
if (qe->qcregs)
- sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
+ of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE);
if (qe->mregs)
- sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
+ of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE);
if (qe->qe_block)
- sbus_free_consistent(qe->qe_sdev,
- PAGE_SIZE,
- qe->qe_block,
- qe->qblock_dvma);
+ dma_free_coherent(&op->dev, PAGE_SIZE,
+ qe->qe_block, qe->qblock_dvma);
if (qe->buffers)
- sbus_free_consistent(qe->qe_sdev,
- sizeof(struct sunqe_buffers),
- qe->buffers,
- qe->buffers_dvma);
+ dma_free_coherent(&op->dev,
+ sizeof(struct sunqe_buffers),
+ qe->buffers,
+ qe->buffers_dvma);
free_netdev(dev);
return res;
}
-static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
- return qec_ether_init(sdev);
+ return qec_ether_init(op);
}
-static int __devexit qec_sbus_remove(struct of_device *dev)
+static int __devexit qec_sbus_remove(struct of_device *op)
{
- struct sunqe *qp = dev_get_drvdata(&dev->dev);
+ struct sunqe *qp = dev_get_drvdata(&op->dev);
struct net_device *net_dev = qp->dev;
unregister_netdev(net_dev);
- sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
- sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
- sbus_free_consistent(qp->qe_sdev,
- PAGE_SIZE,
- qp->qe_block,
- qp->qblock_dvma);
- sbus_free_consistent(qp->qe_sdev,
- sizeof(struct sunqe_buffers),
- qp->buffers,
- qp->buffers_dvma);
+ of_iounmap(&op->resource[0], qp->qcregs, CREG_REG_SIZE);
+ of_iounmap(&op->resource[1], qp->mregs, MREGS_REG_SIZE);
+ dma_free_coherent(&op->dev, PAGE_SIZE,
+ qp->qe_block, qp->qblock_dvma);
+ dma_free_coherent(&op->dev, sizeof(struct sunqe_buffers),
+ qp->buffers, qp->buffers_dvma);
free_netdev(net_dev);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id qec_sbus_match[] = {
+static const struct of_device_id qec_sbus_match[] = {
{
.name = "qe",
},
@@ -991,7 +983,7 @@ static struct of_platform_driver qec_sbus_driver = {
static int __init qec_init(void)
{
- return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&qec_sbus_driver, &of_bus_type);
}
static void __exit qec_exit(void)
@@ -1000,11 +992,11 @@ static void __exit qec_exit(void)
while (root_qec_dev) {
struct sunqec *next = root_qec_dev->next_module;
+ struct of_device *op = root_qec_dev->op;
- free_irq(root_qec_dev->qec_sdev->irqs[0],
- (void *) root_qec_dev);
- sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
-
+ free_irq(op->irqs[0], (void *) root_qec_dev);
+ of_iounmap(&op->resource[0], root_qec_dev->gregs,
+ GLOB_REG_SIZE);
kfree(root_qec_dev);
root_qec_dev = next;
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index 347c8ddc159..5813a7b2faa 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -314,7 +314,7 @@ struct sunqec {
void __iomem *gregs; /* QEC Global Registers */
struct sunqe *qes[4]; /* Each child MACE */
unsigned int qec_bursts; /* Support burst sizes */
- struct sbus_dev *qec_sdev; /* QEC's SBUS device */
+ struct of_device *op; /* QEC's OF device */
struct sunqec *next_module; /* List of all QECs in system */
};
@@ -342,7 +342,7 @@ struct sunqe {
__u32 buffers_dvma; /* DVMA visible address. */
struct sunqec *parent;
u8 mconfig; /* Base MACE mconfig value */
- struct sbus_dev *qe_sdev; /* QE's SBUS device struct */
+ struct of_device *op; /* QE's OF device struct */
struct net_device *dev; /* QE's netdevice struct */
int channel; /* Who am I? */
};
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 6415ce15c2e..a720065553d 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -1,6 +1,6 @@
/* sunvnet.c: Sun LDOM Virtual Network Driver.
*
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/module.h>
@@ -1260,7 +1260,7 @@ static int vnet_port_remove(struct vio_dev *vdev)
return 0;
}
-static struct vio_device_id vnet_port_match[] = {
+static const struct vio_device_id vnet_port_match[] = {
{
.type = "vnet-port",
},
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 4980b12b621..df20cafff7d 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -796,7 +796,7 @@ err_out_unregister_bus:
mdiobus_unregister(lp->mii_bus);
err_out_free_mdio_irq:
kfree(lp->mii_bus->irq);
-err_out_free_mii_bus;
+err_out_free_mii_bus:
mdiobus_free(lp->mii_bus);
err_out:
return err;
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 2ae2ec40015..21efd99b929 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE
config PC300
tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
- depends on HDLC && PCI
+ depends on HDLC && PCI && BROKEN
---help---
Driver for the Cyclades-PC300 synchronous communication boards.
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index c749bdba214..3c3dd403f5d 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1794,10 +1794,10 @@ static struct xenbus_driver netfront = {
static int __init netif_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return 0;
printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
@@ -1809,7 +1809,7 @@ module_init(netif_init);
static void __exit netif_exit(void)
{
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return;
xenbus_unregister_driver(&netfront);
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 9304c455507..ed982273fb8 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -5,6 +5,7 @@
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf
*
* This is the core of the buffer management. Each
* CPU buffer is processed and entered into the
@@ -33,7 +34,7 @@
#include "event_buffer.h"
#include "cpu_buffer.h"
#include "buffer_sync.h"
-
+
static LIST_HEAD(dying_tasks);
static LIST_HEAD(dead_tasks);
static cpumask_t marked_cpus = CPU_MASK_NONE;
@@ -48,10 +49,11 @@ static void process_task_mortuary(void);
* Can be invoked from softirq via RCU callback due to
* call_rcu() of the task struct, hence the _irqsave.
*/
-static int task_free_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_free_notify(struct notifier_block *self, unsigned long val, void *data)
{
unsigned long flags;
- struct task_struct * task = data;
+ struct task_struct *task = data;
spin_lock_irqsave(&task_mortuary, flags);
list_add(&task->tasks, &dying_tasks);
spin_unlock_irqrestore(&task_mortuary, flags);
@@ -62,13 +64,14 @@ static int task_free_notify(struct notifier_block * self, unsigned long val, voi
/* The task is on its way out. A sync of the buffer means we can catch
* any remaining samples for this task.
*/
-static int task_exit_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+task_exit_notify(struct notifier_block *self, unsigned long val, void *data)
{
/* To avoid latency problems, we only process the current CPU,
* hoping that most samples for the task are on this CPU
*/
sync_buffer(raw_smp_processor_id());
- return 0;
+ return 0;
}
@@ -77,11 +80,12 @@ static int task_exit_notify(struct notifier_block * self, unsigned long val, voi
* we don't lose any. This does not have to be exact, it's a QoI issue
* only.
*/
-static int munmap_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+munmap_notify(struct notifier_block *self, unsigned long val, void *data)
{
unsigned long addr = (unsigned long)data;
- struct mm_struct * mm = current->mm;
- struct vm_area_struct * mpnt;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *mpnt;
down_read(&mm->mmap_sem);
@@ -99,11 +103,12 @@ static int munmap_notify(struct notifier_block * self, unsigned long val, void *
return 0;
}
-
+
/* We need to be told about new modules so we don't attribute to a previously
* loaded module, or drop the samples on the floor.
*/
-static int module_load_notify(struct notifier_block * self, unsigned long val, void * data)
+static int
+module_load_notify(struct notifier_block *self, unsigned long val, void *data)
{
#ifdef CONFIG_MODULES
if (val != MODULE_STATE_COMING)
@@ -118,7 +123,7 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v
return 0;
}
-
+
static struct notifier_block task_free_nb = {
.notifier_call = task_free_notify,
};
@@ -135,7 +140,7 @@ static struct notifier_block module_load_nb = {
.notifier_call = module_load_notify,
};
-
+
static void end_sync(void)
{
end_cpu_work();
@@ -208,14 +213,14 @@ static inline unsigned long fast_get_dcookie(struct path *path)
* not strictly necessary but allows oprofile to associate
* shared-library samples with particular applications
*/
-static unsigned long get_exec_dcookie(struct mm_struct * mm)
+static unsigned long get_exec_dcookie(struct mm_struct *mm)
{
unsigned long cookie = NO_COOKIE;
- struct vm_area_struct * vma;
-
+ struct vm_area_struct *vma;
+
if (!mm)
goto out;
-
+
for (vma = mm->mmap; vma; vma = vma->vm_next) {
if (!vma->vm_file)
continue;
@@ -235,13 +240,14 @@ out:
* sure to do this lookup before a mm->mmap modification happens so
* we don't lose track.
*/
-static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
+static unsigned long
+lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
{
unsigned long cookie = NO_COOKIE;
- struct vm_area_struct * vma;
+ struct vm_area_struct *vma;
for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
-
+
if (addr < vma->vm_start || addr >= vma->vm_end)
continue;
@@ -263,9 +269,20 @@ static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, o
return cookie;
}
+static void increment_tail(struct oprofile_cpu_buffer *b)
+{
+ unsigned long new_tail = b->tail_pos + 1;
+
+ rmb(); /* be sure fifo pointers are synchromized */
+
+ if (new_tail < b->buffer_size)
+ b->tail_pos = new_tail;
+ else
+ b->tail_pos = 0;
+}
static unsigned long last_cookie = INVALID_COOKIE;
-
+
static void add_cpu_switch(int i)
{
add_event_entry(ESCAPE_CODE);
@@ -278,16 +295,16 @@ static void add_kernel_ctx_switch(unsigned int in_kernel)
{
add_event_entry(ESCAPE_CODE);
if (in_kernel)
- add_event_entry(KERNEL_ENTER_SWITCH_CODE);
+ add_event_entry(KERNEL_ENTER_SWITCH_CODE);
else
- add_event_entry(KERNEL_EXIT_SWITCH_CODE);
+ add_event_entry(KERNEL_EXIT_SWITCH_CODE);
}
-
+
static void
-add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
+add_user_ctx_switch(struct task_struct const *task, unsigned long cookie)
{
add_event_entry(ESCAPE_CODE);
- add_event_entry(CTX_SWITCH_CODE);
+ add_event_entry(CTX_SWITCH_CODE);
add_event_entry(task->pid);
add_event_entry(cookie);
/* Another code for daemon back-compat */
@@ -296,7 +313,7 @@ add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
add_event_entry(task->tgid);
}
-
+
static void add_cookie_switch(unsigned long cookie)
{
add_event_entry(ESCAPE_CODE);
@@ -304,13 +321,78 @@ static void add_cookie_switch(unsigned long cookie)
add_event_entry(cookie);
}
-
+
static void add_trace_begin(void)
{
add_event_entry(ESCAPE_CODE);
add_event_entry(TRACE_BEGIN_CODE);
}
+#ifdef CONFIG_OPROFILE_IBS
+
+#define IBS_FETCH_CODE_SIZE 2
+#define IBS_OP_CODE_SIZE 5
+#define IBS_EIP(offset) \
+ (((struct op_sample *)&cpu_buf->buffer[(offset)])->eip)
+#define IBS_EVENT(offset) \
+ (((struct op_sample *)&cpu_buf->buffer[(offset)])->event)
+
+/*
+ * Add IBS fetch and op entries to event buffer
+ */
+static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
+ int in_kernel, struct mm_struct *mm)
+{
+ unsigned long rip;
+ int i, count;
+ unsigned long ibs_cookie = 0;
+ off_t offset;
+
+ increment_tail(cpu_buf); /* move to RIP entry */
+
+ rip = IBS_EIP(cpu_buf->tail_pos);
+
+#ifdef __LP64__
+ rip += IBS_EVENT(cpu_buf->tail_pos) << 32;
+#endif
+
+ if (mm) {
+ ibs_cookie = lookup_dcookie(mm, rip, &offset);
+
+ if (ibs_cookie == NO_COOKIE)
+ offset = rip;
+ if (ibs_cookie == INVALID_COOKIE) {
+ atomic_inc(&oprofile_stats.sample_lost_no_mapping);
+ offset = rip;
+ }
+ if (ibs_cookie != last_cookie) {
+ add_cookie_switch(ibs_cookie);
+ last_cookie = ibs_cookie;
+ }
+ } else
+ offset = rip;
+
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(code);
+ add_event_entry(offset); /* Offset from Dcookie */
+
+ /* we send the Dcookie offset, but send the raw Linear Add also*/
+ add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+ add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+
+ if (code == IBS_FETCH_CODE)
+ count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/
+ else
+ count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/
+
+ for (i = 0; i < count; i++) {
+ increment_tail(cpu_buf);
+ add_event_entry(IBS_EIP(cpu_buf->tail_pos));
+ add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+ }
+}
+
+#endif
static void add_sample_entry(unsigned long offset, unsigned long event)
{
@@ -319,13 +401,13 @@ static void add_sample_entry(unsigned long offset, unsigned long event)
}
-static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
+static int add_us_sample(struct mm_struct *mm, struct op_sample *s)
{
unsigned long cookie;
off_t offset;
-
- cookie = lookup_dcookie(mm, s->eip, &offset);
-
+
+ cookie = lookup_dcookie(mm, s->eip, &offset);
+
if (cookie == INVALID_COOKIE) {
atomic_inc(&oprofile_stats.sample_lost_no_mapping);
return 0;
@@ -341,13 +423,13 @@ static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
return 1;
}
-
+
/* Add a sample to the global event buffer. If possible the
* sample is converted into a persistent dentry/offset pair
* for later lookup from userspace.
*/
static int
-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
+add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
{
if (in_kernel) {
add_sample_entry(s->eip, s->event);
@@ -359,9 +441,9 @@ add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
}
return 0;
}
-
-static void release_mm(struct mm_struct * mm)
+
+static void release_mm(struct mm_struct *mm)
{
if (!mm)
return;
@@ -370,9 +452,9 @@ static void release_mm(struct mm_struct * mm)
}
-static struct mm_struct * take_tasks_mm(struct task_struct * task)
+static struct mm_struct *take_tasks_mm(struct task_struct *task)
{
- struct mm_struct * mm = get_task_mm(task);
+ struct mm_struct *mm = get_task_mm(task);
if (mm)
down_read(&mm->mmap_sem);
return mm;
@@ -383,10 +465,10 @@ static inline int is_code(unsigned long val)
{
return val == ESCAPE_CODE;
}
-
+
/* "acquire" as many cpu buffer slots as we can */
-static unsigned long get_slots(struct oprofile_cpu_buffer * b)
+static unsigned long get_slots(struct oprofile_cpu_buffer *b)
{
unsigned long head = b->head_pos;
unsigned long tail = b->tail_pos;
@@ -412,19 +494,6 @@ static unsigned long get_slots(struct oprofile_cpu_buffer * b)
}
-static void increment_tail(struct oprofile_cpu_buffer * b)
-{
- unsigned long new_tail = b->tail_pos + 1;
-
- rmb();
-
- if (new_tail < b->buffer_size)
- b->tail_pos = new_tail;
- else
- b->tail_pos = 0;
-}
-
-
/* Move tasks along towards death. Any tasks on dead_tasks
* will definitely have no remaining references in any
* CPU buffers at this point, because we use two lists,
@@ -435,8 +504,8 @@ static void process_task_mortuary(void)
{
unsigned long flags;
LIST_HEAD(local_dead_tasks);
- struct task_struct * task;
- struct task_struct * ttask;
+ struct task_struct *task;
+ struct task_struct *ttask;
spin_lock_irqsave(&task_mortuary, flags);
@@ -493,7 +562,7 @@ void sync_buffer(int cpu)
{
struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
struct mm_struct *mm = NULL;
- struct task_struct * new;
+ struct task_struct *new;
unsigned long cookie = 0;
int in_kernel = 1;
unsigned int i;
@@ -501,7 +570,7 @@ void sync_buffer(int cpu)
unsigned long available;
mutex_lock(&buffer_mutex);
-
+
add_cpu_switch(cpu);
/* Remember, only we can modify tail_pos */
@@ -509,8 +578,8 @@ void sync_buffer(int cpu)
available = get_slots(cpu_buf);
for (i = 0; i < available; ++i) {
- struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
-
+ struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos];
+
if (is_code(s->eip)) {
if (s->event <= CPU_IS_KERNEL) {
/* kernel/userspace switch */
@@ -521,8 +590,18 @@ void sync_buffer(int cpu)
} else if (s->event == CPU_TRACE_BEGIN) {
state = sb_bt_start;
add_trace_begin();
+#ifdef CONFIG_OPROFILE_IBS
+ } else if (s->event == IBS_FETCH_BEGIN) {
+ state = sb_bt_start;
+ add_ibs_begin(cpu_buf,
+ IBS_FETCH_CODE, in_kernel, mm);
+ } else if (s->event == IBS_OP_BEGIN) {
+ state = sb_bt_start;
+ add_ibs_begin(cpu_buf,
+ IBS_OP_CODE, in_kernel, mm);
+#endif
} else {
- struct mm_struct * oldmm = mm;
+ struct mm_struct *oldmm = mm;
/* userspace context switch */
new = (struct task_struct *)s->event;
@@ -533,13 +612,11 @@ void sync_buffer(int cpu)
cookie = get_exec_dcookie(mm);
add_user_ctx_switch(new, cookie);
}
- } else {
- if (state >= sb_bt_start &&
- !add_sample(mm, s, in_kernel)) {
- if (state == sb_bt_start) {
- state = sb_bt_ignore;
- atomic_inc(&oprofile_stats.bt_lost_no_mapping);
- }
+ } else if (state >= sb_bt_start &&
+ !add_sample(mm, s, in_kernel)) {
+ if (state == sb_bt_start) {
+ state = sb_bt_ignore;
+ atomic_inc(&oprofile_stats.bt_lost_no_mapping);
}
}
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 7ba78e6d210..e1bd5a937f6 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -5,6 +5,7 @@
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
+ * @author Barry Kasindorf <barry.kasindorf@amd.com>
*
* Each CPU has a local buffer that stores PC value/event
* pairs. We also log context switches when we notice them.
@@ -209,7 +210,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
return 1;
}
-static int oprofile_begin_trace(struct oprofile_cpu_buffer * cpu_buf)
+static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
{
if (nr_available_slots(cpu_buf) < 4) {
cpu_buf->sample_lost_overflow++;
@@ -254,6 +255,75 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
oprofile_add_ext_sample(pc, regs, event, is_kernel);
}
+#ifdef CONFIG_OPROFILE_IBS
+
+#define MAX_IBS_SAMPLE_SIZE 14
+static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf,
+ unsigned long pc, int is_kernel, unsigned int *ibs, int ibs_code)
+{
+ struct task_struct *task;
+
+ cpu_buf->sample_received++;
+
+ if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) {
+ cpu_buf->sample_lost_overflow++;
+ return 0;
+ }
+
+ is_kernel = !!is_kernel;
+
+ /* notice a switch from user->kernel or vice versa */
+ if (cpu_buf->last_is_kernel != is_kernel) {
+ cpu_buf->last_is_kernel = is_kernel;
+ add_code(cpu_buf, is_kernel);
+ }
+
+ /* notice a task switch */
+ if (!is_kernel) {
+ task = current;
+
+ if (cpu_buf->last_task != task) {
+ cpu_buf->last_task = task;
+ add_code(cpu_buf, (unsigned long)task);
+ }
+ }
+
+ add_code(cpu_buf, ibs_code);
+ add_sample(cpu_buf, ibs[0], ibs[1]);
+ add_sample(cpu_buf, ibs[2], ibs[3]);
+ add_sample(cpu_buf, ibs[4], ibs[5]);
+
+ if (ibs_code == IBS_OP_BEGIN) {
+ add_sample(cpu_buf, ibs[6], ibs[7]);
+ add_sample(cpu_buf, ibs[8], ibs[9]);
+ add_sample(cpu_buf, ibs[10], ibs[11]);
+ }
+
+ return 1;
+}
+
+void oprofile_add_ibs_sample(struct pt_regs *const regs,
+ unsigned int * const ibs_sample, u8 code)
+{
+ int is_kernel = !user_mode(regs);
+ unsigned long pc = profile_pc(regs);
+
+ struct oprofile_cpu_buffer *cpu_buf =
+ &per_cpu(cpu_buffer, smp_processor_id());
+
+ if (!backtrace_depth) {
+ log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code);
+ return;
+ }
+
+ /* if log_sample() fails we can't backtrace since we lost the source
+ * of this event */
+ if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code))
+ oprofile_ops.backtrace(regs, backtrace_depth);
+}
+
+#endif
+
void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
{
struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
@@ -296,7 +366,7 @@ static void wq_sync_buffer(struct work_struct *work)
struct oprofile_cpu_buffer * b =
container_of(work, struct oprofile_cpu_buffer, work.work);
if (b->cpu != smp_processor_id()) {
- printk("WQ on CPU%d, prefer CPU%d\n",
+ printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n",
smp_processor_id(), b->cpu);
}
sync_buffer(b->cpu);
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index c3e366b5226..9c44d004da6 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -55,5 +55,7 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
/* transient events for the CPU buffer -> event buffer */
#define CPU_IS_KERNEL 1
#define CPU_TRACE_BEGIN 2
+#define IBS_FETCH_BEGIN 3
+#define IBS_OP_BEGIN 4
#endif /* OPROFILE_CPU_BUFFER_H */
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 9d595aa91e4..065f229580d 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -26,6 +26,8 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/parport.h>
@@ -34,7 +36,6 @@
#include <asm/io.h>
#include <asm/oplib.h> /* OpenProm Library */
-#include <asm/sbus.h>
#include <asm/dma.h> /* BPP uses LSI 64854 for DMA */
#include <asm/irq.h>
#include <asm/sunbpp.h>
@@ -285,38 +286,37 @@ static struct parport_operations parport_sunbpp_ops =
.owner = THIS_MODULE,
};
-static int __devinit init_one_port(struct sbus_dev *sdev)
+static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match)
{
- struct parport *p;
- /* at least in theory there may be a "we don't dma" case */
struct parport_operations *ops;
- void __iomem *base;
- int irq, dma, err = 0, size;
struct bpp_regs __iomem *regs;
+ int irq, dma, err = 0, size;
unsigned char value_tcr;
+ void __iomem *base;
+ struct parport *p;
- irq = sdev->irqs[0];
- base = sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "sunbpp");
+ irq = op->irqs[0];
+ base = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "sunbpp");
if (!base)
return -ENODEV;
- size = sdev->reg_addrs[0].reg_size;
+ size = resource_size(&op->resource[0]);
dma = PARPORT_DMA_NONE;
ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
if (!ops)
goto out_unmap;
- memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
+ memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations));
dprintk(("register_port\n"));
if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
goto out_free_ops;
p->size = size;
- p->dev = &sdev->ofdev.dev;
+ p->dev = &op->dev;
if ((err = request_irq(p->irq, parport_irq_handler,
IRQF_SHARED, p->name, p)) != 0) {
@@ -333,7 +333,7 @@ static int __devinit init_one_port(struct sbus_dev *sdev)
printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
- dev_set_drvdata(&sdev->ofdev.dev, p);
+ dev_set_drvdata(&op->dev, p);
parport_announce_port(p);
@@ -346,21 +346,14 @@ out_free_ops:
kfree(ops);
out_unmap:
- sbus_iounmap(base, size);
+ of_iounmap(&op->resource[0], base, size);
return err;
}
-static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
- return init_one_port(sdev);
-}
-
-static int __devexit bpp_remove(struct of_device *dev)
+static int __devexit bpp_remove(struct of_device *op)
{
- struct parport *p = dev_get_drvdata(&dev->dev);
+ struct parport *p = dev_get_drvdata(&op->dev);
struct parport_operations *ops = p->ops;
parport_remove_port(p);
@@ -370,16 +363,16 @@ static int __devexit bpp_remove(struct of_device *dev)
free_irq(p->irq, p);
}
- sbus_iounmap((void __iomem *) p->base, p->size);
+ of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);
parport_put_port(p);
kfree(ops);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id bpp_match[] = {
+static const struct of_device_id bpp_match[] = {
{
.name = "SUNW,bpp",
},
@@ -397,7 +390,7 @@ static struct of_platform_driver bpp_sbus_driver = {
static int __init parport_sunbpp_init(void)
{
- return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&bpp_sbus_driver, &of_bus_type);
}
static void __exit parport_sunbpp_exit(void)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 1982f8b4278..63bb5791044 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -58,7 +58,7 @@ config BATTERY_TOSA
config BATTERY_WM97XX
bool "WM97xx generic battery driver"
- depends on TOUCHSCREEN_WM97XX
+ depends on TOUCHSCREEN_WM97XX=y
help
Say Y to enable support for battery measured by WM97xx aux port.
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 9a9755c92fa..b57fba5c6d0 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -329,7 +329,7 @@ comment "Platform RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
- depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
+ depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
default y if X86
help
Say "yes" here to get direct support for the real time clock
@@ -406,14 +406,26 @@ config RTC_DRV_M48T86
will be called rtc-m48t86.
config RTC_DRV_M48T59
- tristate "ST M48T59"
+ tristate "ST M48T59/M48T08/M48T02"
help
If you say Y here you will get support for the
- ST M48T59 RTC chip.
+ ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
+
+ These chips are usually found in Sun SPARC and UltraSPARC
+ workstations.
This driver can also be built as a module, if so, the module
will be called "rtc-m48t59".
+config RTC_DRV_BQ4802
+ tristate "TI BQ4802"
+ help
+ If you say Y here you will get support for the TI
+ BQ4802 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-bq4802.
+
config RTC_DRV_V3020
tristate "EM Microelectronic V3020"
help
@@ -583,4 +595,18 @@ config RTC_DRV_PPC
the RTC. This exposes that functionality through the generic RTC
class.
+config RTC_DRV_SUN4V
+ bool "SUN4V Hypervisor RTC"
+ depends on SPARC64
+ help
+ If you say Y here you will get support for the Hypervisor
+ based RTC on SUN4V systems.
+
+config RTC_DRV_STARFIRE
+ bool "Starfire RTC"
+ depends on SPARC64
+ help
+ If you say Y here you will get support for the RTC found on
+ Starfire systems.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 18622ef84ca..10f41f85c38 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -38,6 +38,9 @@ obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
+obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
+obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
new file mode 100644
index 00000000000..189a018bdf3
--- /dev/null
+++ b/drivers/rtc/rtc-bq4802.c
@@ -0,0 +1,230 @@
+/* rtc-bq4802.c: TI BQ4802 RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("TI BQ4802 RTC driver");
+MODULE_LICENSE("GPL");
+
+struct bq4802 {
+ void __iomem *regs;
+ unsigned long ioport;
+ struct rtc_device *rtc;
+ spinlock_t lock;
+ struct resource *r;
+ u8 (*read)(struct bq4802 *, int);
+ void (*write)(struct bq4802 *, int, u8);
+};
+
+static u8 bq4802_read_io(struct bq4802 *p, int off)
+{
+ return inb(p->ioport + off);
+}
+
+static void bq4802_write_io(struct bq4802 *p, int off, u8 val)
+{
+ outb(val, p->ioport + off);
+}
+
+static u8 bq4802_read_mem(struct bq4802 *p, int off)
+{
+ return readb(p->regs + off);
+}
+
+static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
+{
+ writeb(val, p->regs + off);
+}
+
+static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bq4802 *p = platform_get_drvdata(pdev);
+ unsigned long flags;
+ unsigned int century;
+ u8 val;
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ val = p->read(p, 0x0e);
+ p->write(p, 0xe, val | 0x08);
+
+ tm->tm_sec = p->read(p, 0x00);
+ tm->tm_min = p->read(p, 0x02);
+ tm->tm_hour = p->read(p, 0x04);
+ tm->tm_mday = p->read(p, 0x06);
+ tm->tm_mon = p->read(p, 0x09);
+ tm->tm_year = p->read(p, 0x0a);
+ tm->tm_wday = p->read(p, 0x08);
+ century = p->read(p, 0x0f);
+
+ p->write(p, 0x0e, val);
+
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ BCD_TO_BIN(tm->tm_sec);
+ BCD_TO_BIN(tm->tm_min);
+ BCD_TO_BIN(tm->tm_hour);
+ BCD_TO_BIN(tm->tm_mday);
+ BCD_TO_BIN(tm->tm_mon);
+ BCD_TO_BIN(tm->tm_year);
+ BCD_TO_BIN(tm->tm_wday);
+ BCD_TO_BIN(century);
+
+ tm->tm_year += (century * 100);
+ tm->tm_year -= 1900;
+
+ tm->tm_mon--;
+
+ return 0;
+}
+
+static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bq4802 *p = platform_get_drvdata(pdev);
+ u8 sec, min, hrs, day, mon, yrs, century, val;
+ unsigned long flags;
+ unsigned int year;
+
+ year = tm->tm_year + 1900;
+ century = year / 100;
+ yrs = year % 100;
+
+ mon = tm->tm_mon + 1; /* tm_mon starts at zero */
+ day = tm->tm_mday;
+ hrs = tm->tm_hour;
+ min = tm->tm_min;
+ sec = tm->tm_sec;
+
+ BIN_TO_BCD(sec);
+ BIN_TO_BCD(min);
+ BIN_TO_BCD(hrs);
+ BIN_TO_BCD(day);
+ BIN_TO_BCD(mon);
+ BIN_TO_BCD(yrs);
+ BIN_TO_BCD(century);
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ val = p->read(p, 0x0e);
+ p->write(p, 0x0e, val | 0x08);
+
+ p->write(p, 0x00, sec);
+ p->write(p, 0x02, min);
+ p->write(p, 0x04, hrs);
+ p->write(p, 0x06, day);
+ p->write(p, 0x09, mon);
+ p->write(p, 0x0a, yrs);
+ p->write(p, 0x0f, century);
+
+ p->write(p, 0x0e, val);
+
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ return 0;
+}
+
+static const struct rtc_class_ops bq4802_ops = {
+ .read_time = bq4802_read_time,
+ .set_time = bq4802_set_time,
+};
+
+static int __devinit bq4802_probe(struct platform_device *pdev)
+{
+ struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
+
+ if (!p)
+ goto out;
+
+ spin_lock_init(&p->lock);
+
+ p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!p->r) {
+ p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ err = -EINVAL;
+ if (!p->r)
+ goto out_free;
+ }
+ if (p->r->flags & IORESOURCE_IO) {
+ p->ioport = p->r->start;
+ p->read = bq4802_read_io;
+ p->write = bq4802_write_io;
+ } else if (p->r->flags & IORESOURCE_MEM) {
+ p->regs = ioremap(p->r->start, resource_size(p->r));
+ p->read = bq4802_read_mem;
+ p->write = bq4802_write_mem;
+ } else {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ p->rtc = rtc_device_register("bq4802", &pdev->dev,
+ &bq4802_ops, THIS_MODULE);
+ if (IS_ERR(p->rtc)) {
+ err = PTR_ERR(p->rtc);
+ goto out_iounmap;
+ }
+
+ platform_set_drvdata(pdev, p);
+ err = 0;
+out:
+ return err;
+
+out_iounmap:
+ if (p->r->flags & IORESOURCE_MEM)
+ iounmap(p->regs);
+out_free:
+ kfree(p);
+ goto out;
+}
+
+static int __devexit bq4802_remove(struct platform_device *pdev)
+{
+ struct bq4802 *p = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(p->rtc);
+ if (p->r->flags & IORESOURCE_MEM)
+ iounmap(p->regs);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(p);
+
+ return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:rtc-bq4802");
+
+static struct platform_driver bq4802_driver = {
+ .driver = {
+ .name = "rtc-bq4802",
+ .owner = THIS_MODULE,
+ },
+ .probe = bq4802_probe,
+ .remove = __devexit_p(bq4802_remove),
+};
+
+static int __init bq4802_init(void)
+{
+ return platform_driver_register(&bq4802_driver);
+}
+
+static void __exit bq4802_exit(void)
+{
+ platform_driver_unregister(&bq4802_driver);
+}
+
+module_init(bq4802_init);
+module_exit(bq4802_exit);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index b184367637d..b23af0c2a86 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -636,7 +636,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
*/
#if defined(CONFIG_ATARI)
address_space = 64;
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__)
address_space = 128;
#else
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@@ -699,7 +699,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
/* FIXME teach the alarm code how to handle binary mode;
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
- if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
+ if (is_valid_irq(rtc_irq) &&
+ (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) {
dev_dbg(dev, "only 24-hr BCD mode supported\n");
retval = -ENXIO;
goto cleanup1;
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 013e6c103b9..ce4eff6a8d5 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -24,8 +24,9 @@
#define NO_IRQ (-1)
#endif
-#define M48T59_READ(reg) pdata->read_byte(dev, reg)
-#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val)
+#define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg))
+#define M48T59_WRITE(val, reg) \
+ (pdata->write_byte(dev, pdata->offset + reg, val))
#define M48T59_SET_BITS(mask, reg) \
M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
@@ -34,7 +35,6 @@
struct m48t59_private {
void __iomem *ioaddr;
- unsigned int size; /* iomem size */
int irq;
struct rtc_device *rtc;
spinlock_t lock; /* serialize the NVRAM and RTC access */
@@ -82,7 +82,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY));
val = M48T59_READ(M48T59_WDAY);
- if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
+ if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
+ (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
dev_dbg(dev, "Century bit is enabled\n");
tm->tm_year += 100; /* one century */
}
@@ -126,7 +127,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
- if (tm->tm_year/100)
+ if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100))
val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
val |= (BIN2BCD(tm->tm_wday) & 0x07);
M48T59_WRITE(val, M48T59_WDAY);
@@ -310,6 +311,11 @@ static const struct rtc_class_ops m48t59_rtc_ops = {
.proc = m48t59_rtc_proc,
};
+static const struct rtc_class_ops m48t02_rtc_ops = {
+ .read_time = m48t59_rtc_read_time,
+ .set_time = m48t59_rtc_set_time,
+};
+
static ssize_t m48t59_nvram_read(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
@@ -321,7 +327,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj,
ssize_t cnt = 0;
unsigned long flags;
- for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+ for (; size > 0 && pos < pdata->offset; cnt++, size--) {
spin_lock_irqsave(&m48t59->lock, flags);
*buf++ = M48T59_READ(cnt);
spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -341,7 +347,7 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj,
ssize_t cnt = 0;
unsigned long flags;
- for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+ for (; size > 0 && pos < pdata->offset; cnt++, size--) {
spin_lock_irqsave(&m48t59->lock, flags);
M48T59_WRITE(*buf++, cnt);
spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -358,7 +364,6 @@ static struct bin_attribute m48t59_nvram_attr = {
},
.read = m48t59_nvram_read,
.write = m48t59_nvram_write,
- .size = M48T59_NVRAM_SIZE,
};
static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
@@ -367,6 +372,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
struct m48t59_private *m48t59 = NULL;
struct resource *res;
int ret = -ENOMEM;
+ char *name;
+ const struct rtc_class_ops *ops;
/* This chip could be memory-mapped or I/O-mapped */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -391,6 +398,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
/* Ensure we only kmalloc platform data once */
pdev->dev.platform_data = pdata;
}
+ if (!pdata->type)
+ pdata->type = M48T59RTC_TYPE_M48T59;
/* Try to use the generic memory read/write ops */
if (!pdata->write_byte)
@@ -403,10 +412,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
if (!m48t59)
return -ENOMEM;
- m48t59->size = res->end - res->start + 1;
- m48t59->ioaddr = ioremap(res->start, m48t59->size);
- if (!m48t59->ioaddr)
- goto out;
+ m48t59->ioaddr = pdata->ioaddr;
+
+ if (!m48t59->ioaddr) {
+ /* ioaddr not mapped externally */
+ m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1);
+ if (!m48t59->ioaddr)
+ goto out;
+ }
/* Try to get irq number. We also can work in
* the mode without IRQ.
@@ -421,14 +434,36 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
if (ret)
goto out;
}
+ switch (pdata->type) {
+ case M48T59RTC_TYPE_M48T59:
+ name = "m48t59";
+ ops = &m48t59_rtc_ops;
+ pdata->offset = 0x1ff0;
+ break;
+ case M48T59RTC_TYPE_M48T02:
+ name = "m48t02";
+ ops = &m48t02_rtc_ops;
+ pdata->offset = 0x7f0;
+ break;
+ case M48T59RTC_TYPE_M48T08:
+ name = "m48t08";
+ ops = &m48t02_rtc_ops;
+ pdata->offset = 0x1ff0;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unknown RTC type\n");
+ ret = -ENODEV;
+ goto out;
+ }
- m48t59->rtc = rtc_device_register("m48t59", &pdev->dev,
- &m48t59_rtc_ops, THIS_MODULE);
+ m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE);
if (IS_ERR(m48t59->rtc)) {
ret = PTR_ERR(m48t59->rtc);
goto out;
}
+ m48t59_nvram_attr.size = pdata->offset;
+
ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
if (ret)
goto out;
@@ -452,11 +487,12 @@ out:
static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
{
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
if (!IS_ERR(m48t59->rtc))
rtc_device_unregister(m48t59->rtc);
- if (m48t59->ioaddr)
+ if (m48t59->ioaddr && !pdata->ioaddr)
iounmap(m48t59->ioaddr);
if (m48t59->irq != NO_IRQ)
free_irq(m48t59->irq, &pdev->dev);
@@ -491,5 +527,5 @@ module_init(m48t59_rtc_init);
module_exit(m48t59_rtc_exit);
MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
-MODULE_DESCRIPTION("M48T59 RTC driver");
+MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
new file mode 100644
index 00000000000..7ccb0dd700a
--- /dev/null
+++ b/drivers/rtc/rtc-starfire.c
@@ -0,0 +1,120 @@
+/* rtc-starfire.c: Starfire platform RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/oplib.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("Starfire RTC driver");
+MODULE_LICENSE("GPL");
+
+struct starfire_rtc {
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+static u32 starfire_get_time(void)
+{
+ static char obp_gettod[32];
+ static u32 unix_tod;
+
+ sprintf(obp_gettod, "h# %08x unix-gettod",
+ (unsigned int) (long) &unix_tod);
+ prom_feval(obp_gettod);
+
+ return unix_tod;
+}
+
+static int starfire_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct starfire_rtc *p = dev_get_drvdata(dev);
+ unsigned long flags, secs;
+
+ spin_lock_irqsave(&p->lock, flags);
+ secs = starfire_get_time();
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ rtc_time_to_tm(secs, tm);
+
+ return 0;
+}
+
+static int starfire_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long secs;
+ int err;
+
+ err = rtc_tm_to_time(tm, &secs);
+ if (err)
+ return err;
+
+ /* Do nothing, time is set using the service processor
+ * console on this platform.
+ */
+ return 0;
+}
+
+static const struct rtc_class_ops starfire_rtc_ops = {
+ .read_time = starfire_read_time,
+ .set_time = starfire_set_time,
+};
+
+static int __devinit starfire_rtc_probe(struct platform_device *pdev)
+{
+ struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+ if (!p)
+ return -ENOMEM;
+
+ spin_lock_init(&p->lock);
+
+ p->rtc = rtc_device_register("starfire", &pdev->dev,
+ &starfire_rtc_ops, THIS_MODULE);
+ if (IS_ERR(p->rtc)) {
+ int err = PTR_ERR(p->rtc);
+ kfree(p);
+ return err;
+ }
+ platform_set_drvdata(pdev, p);
+ return 0;
+}
+
+static int __devexit starfire_rtc_remove(struct platform_device *pdev)
+{
+ struct starfire_rtc *p = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(p->rtc);
+ kfree(p);
+
+ return 0;
+}
+
+static struct platform_driver starfire_rtc_driver = {
+ .driver = {
+ .name = "rtc-starfire",
+ .owner = THIS_MODULE,
+ },
+ .probe = starfire_rtc_probe,
+ .remove = __devexit_p(starfire_rtc_remove),
+};
+
+static int __init starfire_rtc_init(void)
+{
+ return platform_driver_register(&starfire_rtc_driver);
+}
+
+static void __exit starfire_rtc_exit(void)
+{
+ platform_driver_unregister(&starfire_rtc_driver);
+}
+
+module_init(starfire_rtc_init);
+module_exit(starfire_rtc_exit);
diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
new file mode 100644
index 00000000000..2012ccbb4a5
--- /dev/null
+++ b/drivers/rtc/rtc-sun4v.c
@@ -0,0 +1,153 @@
+/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/hypervisor.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("SUN4V RTC driver");
+MODULE_LICENSE("GPL");
+
+struct sun4v_rtc {
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+static unsigned long hypervisor_get_time(void)
+{
+ unsigned long ret, time;
+ int retries = 10000;
+
+retry:
+ ret = sun4v_tod_get(&time);
+ if (ret == HV_EOK)
+ return time;
+ if (ret == HV_EWOULDBLOCK) {
+ if (--retries > 0) {
+ udelay(100);
+ goto retry;
+ }
+ printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
+ return 0;
+ }
+ printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
+ return 0;
+}
+
+static int sun4v_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct sun4v_rtc *p = dev_get_drvdata(dev);
+ unsigned long flags, secs;
+
+ spin_lock_irqsave(&p->lock, flags);
+ secs = hypervisor_get_time();
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ rtc_time_to_tm(secs, tm);
+
+ return 0;
+}
+
+static int hypervisor_set_time(unsigned long secs)
+{
+ unsigned long ret;
+ int retries = 10000;
+
+retry:
+ ret = sun4v_tod_set(secs);
+ if (ret == HV_EOK)
+ return 0;
+ if (ret == HV_EWOULDBLOCK) {
+ if (--retries > 0) {
+ udelay(100);
+ goto retry;
+ }
+ printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
+ return -EAGAIN;
+ }
+ printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
+ return -EOPNOTSUPP;
+}
+
+static int sun4v_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct sun4v_rtc *p = dev_get_drvdata(dev);
+ unsigned long flags, secs;
+ int err;
+
+ err = rtc_tm_to_time(tm, &secs);
+ if (err)
+ return err;
+
+ spin_lock_irqsave(&p->lock, flags);
+ err = hypervisor_set_time(secs);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ return err;
+}
+
+static const struct rtc_class_ops sun4v_rtc_ops = {
+ .read_time = sun4v_read_time,
+ .set_time = sun4v_set_time,
+};
+
+static int __devinit sun4v_rtc_probe(struct platform_device *pdev)
+{
+ struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+ if (!p)
+ return -ENOMEM;
+
+ spin_lock_init(&p->lock);
+
+ p->rtc = rtc_device_register("sun4v", &pdev->dev,
+ &sun4v_rtc_ops, THIS_MODULE);
+ if (IS_ERR(p->rtc)) {
+ int err = PTR_ERR(p->rtc);
+ kfree(p);
+ return err;
+ }
+ platform_set_drvdata(pdev, p);
+ return 0;
+}
+
+static int __devexit sun4v_rtc_remove(struct platform_device *pdev)
+{
+ struct sun4v_rtc *p = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(p->rtc);
+ kfree(p);
+
+ return 0;
+}
+
+static struct platform_driver sun4v_rtc_driver = {
+ .driver = {
+ .name = "rtc-sun4v",
+ .owner = THIS_MODULE,
+ },
+ .probe = sun4v_rtc_probe,
+ .remove = __devexit_p(sun4v_rtc_remove),
+};
+
+static int __init sun4v_rtc_init(void)
+{
+ return platform_driver_register(&sun4v_rtc_driver);
+}
+
+static void __exit sun4v_rtc_exit(void)
+{
+ platform_driver_unregister(&sun4v_rtc_driver);
+}
+
+module_init(sun4v_rtc_init);
+module_exit(sun4v_rtc_exit);
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index d18e6d2e0b4..40759c33477 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -418,25 +418,22 @@ fs3270_open(struct inode *inode, struct file *filp)
{
struct fs3270 *fp;
struct idal_buffer *ib;
- int minor, rc;
+ int minor, rc = 0;
if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
return -ENODEV;
- lock_kernel();
minor = iminor(filp->f_path.dentry->d_inode);
/* Check for minor 0 multiplexer. */
if (minor == 0) {
- struct tty_struct *tty;
- mutex_lock(&tty_mutex);
- tty = get_current_tty();
+ struct tty_struct *tty = get_current_tty();
if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
- mutex_unlock(&tty_mutex);
- rc = -ENODEV;
- goto out;
+ tty_kref_put(tty);
+ return -ENODEV;
}
minor = tty->index + RAW3270_FIRSTMINOR;
- mutex_unlock(&tty_mutex);
+ tty_kref_put(tty);
}
+ lock_kernel();
/* Check if some other program is already using fullscreen mode. */
fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
if (!IS_ERR(fp)) {
@@ -478,7 +475,7 @@ fs3270_open(struct inode *inode, struct file *filp)
filp->private_data = fp;
out:
unlock_kernel();
- return 0;
+ return rc;
}
/*
diff --git a/drivers/sbus/Makefile b/drivers/sbus/Makefile
index 7b1d24d9530..e94dc25805f 100644
--- a/drivers/sbus/Makefile
+++ b/drivers/sbus/Makefile
@@ -2,8 +2,4 @@
# Makefile for the linux kernel.
#
-ifneq ($(ARCH),m68k)
-obj-y := sbus.o dvma.o
-endif
-
obj-$(CONFIG_SBUSCHAR) += char/
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 400c65bfb8c..73cde85d04d 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -13,16 +13,6 @@ config SUN_OPENPROMIO
If unsure, say Y.
-config SUN_MOSTEK_RTC
- tristate "Mostek real time clock support"
- depends on SPARC32
- help
- The Mostek RTC chip is used on all known Sun computers except
- some JavaStations. For a JavaStation you need to say Y both here
- and to "Enhanced Real Time Clock Support".
-
- Say Y here unless you are building a special purpose kernel.
-
config OBP_FLASH
tristate "OBP Flash Device support"
depends on SPARC64
@@ -30,26 +20,9 @@ config OBP_FLASH
The OpenBoot PROM on Ultra systems is flashable. If you want to be
able to upgrade the OBP firmware, say Y here.
-config SUN_BPP
- tristate "Bidirectional parallel port support (OBSOLETE)"
- depends on EXPERIMENTAL
- help
- Say Y here to support Sun's obsolete variant of IEEE1284
- bidirectional parallel port protocol as /dev/bppX. Can be built on
- x86 machines.
-
-config SUN_VIDEOPIX
- tristate "Videopix Frame Grabber (EXPERIMENTAL)"
- depends on EXPERIMENTAL && (BROKEN || !64BIT)
- help
- Say Y here to support the Videopix Frame Grabber from Sun
- Microsystems, commonly found on SPARCstations. This card, which is
- based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
- SVIDEO signals.
-
config TADPOLE_TS102_UCTRL
tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && SPARC32
+ depends on EXPERIMENTAL
help
Say Y here to directly support the TS102 Microcontroller interface
on the Tadpole Sparcbook 3. This device handles power-management
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 7ab060e9a5f..78b6183c986 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -7,18 +7,12 @@
# Rewritten to use lists instead of if-statements.
#
-vfc-objs := vfc_dev.o vfc_i2c.o
bbc-objs := bbc_i2c.o bbc_envctrl.o
obj-$(CONFIG_ENVCTRL) += envctrl.o
obj-$(CONFIG_DISPLAY7SEG) += display7seg.o
-obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwatchdog.o
-obj-$(CONFIG_WATCHDOG_RIO) += riowatchdog.o
obj-$(CONFIG_OBP_FLASH) += flash.o
obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o
-obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o
-obj-$(CONFIG_SUN_BPP) += bpp.o
-obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o
obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o
obj-$(CONFIG_SUN_JSFLASH) += jsflash.o
obj-$(CONFIG_BBC_I2C) += bbc.o
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index 0bde26989a2..15dab96d05e 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -1,15 +1,15 @@
-/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $
- * bbc_envctrl.c: UltraSPARC-III environment control driver.
+/* bbc_envctrl.c: UltraSPARC-III environment control driver.
*
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/kmod.h>
#include <linux/reboot.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/oplib.h>
-#include <asm/ebus.h>
#include "bbc_i2c.h"
#include "max1617.h"
@@ -75,43 +75,8 @@ static struct temp_limits amb_temp_limits[2] = {
{ 65, 55, 40, 5, -5, -10 },
};
-enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
-
-struct bbc_cpu_temperature {
- struct bbc_cpu_temperature *next;
-
- struct bbc_i2c_client *client;
- int index;
-
- /* Current readings, and history. */
- s8 curr_cpu_temp;
- s8 curr_amb_temp;
- s8 prev_cpu_temp;
- s8 prev_amb_temp;
- s8 avg_cpu_temp;
- s8 avg_amb_temp;
-
- int sample_tick;
-
- enum fan_action fan_todo[2];
-#define FAN_AMBIENT 0
-#define FAN_CPU 1
-};
-
-struct bbc_cpu_temperature *all_bbc_temps;
-
-struct bbc_fan_control {
- struct bbc_fan_control *next;
-
- struct bbc_i2c_client *client;
- int index;
-
- int psupply_fan_on;
- int cpu_fan_speed;
- int system_fan_speed;
-};
-
-struct bbc_fan_control *all_bbc_fans;
+static LIST_HEAD(all_temps);
+static LIST_HEAD(all_fans);
#define CPU_FAN_REG 0xf0
#define SYS_FAN_REG 0xf2
@@ -330,7 +295,7 @@ static enum fan_action prioritize_fan_action(int which_fan)
* recommend we do, and perform that action on all the
* fans.
*/
- for (tp = all_bbc_temps; tp; tp = tp->next) {
+ list_for_each_entry(tp, &all_temps, glob_list) {
if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
decision = FAN_FULLBLAST;
break;
@@ -439,7 +404,7 @@ static void fans_full_blast(void)
/* Since we will not be monitoring things anymore, put
* the fans on full blast.
*/
- for (fp = all_bbc_fans; fp; fp = fp->next) {
+ list_for_each_entry(fp, &all_fans, glob_list) {
fp->cpu_fan_speed = FAN_SPEED_MAX;
fp->system_fan_speed = FAN_SPEED_MAX;
fp->psupply_fan_on = 1;
@@ -463,11 +428,11 @@ static int kenvctrld(void *__unused)
if (kthread_should_stop())
break;
- for (tp = all_bbc_temps; tp; tp = tp->next) {
+ list_for_each_entry(tp, &all_temps, glob_list) {
get_current_temps(tp);
analyze_temps(tp, &last_warning_jiffies);
}
- for (fp = all_bbc_fans; fp; fp = fp->next)
+ list_for_each_entry(fp, &all_fans, glob_list)
maybe_new_fan_speeds(fp);
}
printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
@@ -477,7 +442,8 @@ static int kenvctrld(void *__unused)
return 0;
}
-static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
+static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op,
+ int temp_idx)
{
struct bbc_cpu_temperature *tp;
@@ -485,20 +451,17 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
if (!tp)
return;
- tp->client = bbc_i2c_attach(echild);
+ tp->client = bbc_i2c_attach(bp, op);
if (!tp->client) {
kfree(tp);
return;
}
+
tp->index = temp_idx;
- {
- struct bbc_cpu_temperature **tpp = &all_bbc_temps;
- while (*tpp)
- tpp = &((*tpp)->next);
- tp->next = NULL;
- *tpp = tp;
- }
+
+ list_add(&tp->glob_list, &all_temps);
+ list_add(&tp->bp_list, &bp->temps);
/* Tell it to convert once every 5 seconds, clear all cfg
* bits.
@@ -524,7 +487,8 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
tp->fan_todo[FAN_CPU] = FAN_SAME;
}
-static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
+static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op,
+ int fan_idx)
{
struct bbc_fan_control *fp;
@@ -532,7 +496,7 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
if (!fp)
return;
- fp->client = bbc_i2c_attach(echild);
+ fp->client = bbc_i2c_attach(bp, op);
if (!fp->client) {
kfree(fp);
return;
@@ -540,13 +504,8 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
fp->index = fan_idx;
- {
- struct bbc_fan_control **fpp = &all_bbc_fans;
- while (*fpp)
- fpp = &((*fpp)->next);
- fp->next = NULL;
- *fpp = fp;
- }
+ list_add(&fp->glob_list, &all_fans);
+ list_add(&fp->bp_list, &bp->fans);
/* The i2c device controlling the fans is write-only.
* So the only way to keep track of the current power
@@ -563,18 +522,18 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
set_fan_speeds(fp);
}
-int bbc_envctrl_init(void)
+int bbc_envctrl_init(struct bbc_i2c_bus *bp)
{
- struct linux_ebus_child *echild;
+ struct of_device *op;
int temp_index = 0;
int fan_index = 0;
int devidx = 0;
- while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
- if (!strcmp(echild->prom_node->name, "temperature"))
- attach_one_temp(echild, temp_index++);
- if (!strcmp(echild->prom_node->name, "fan-control"))
- attach_one_fan(echild, fan_index++);
+ while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
+ if (!strcmp(op->node->name, "temperature"))
+ attach_one_temp(bp, op, temp_index++);
+ if (!strcmp(op->node->name, "fan-control"))
+ attach_one_fan(bp, op, fan_index++);
}
if (temp_index != 0 && fan_index != 0) {
kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -597,26 +556,22 @@ static void destroy_one_fan(struct bbc_fan_control *fp)
kfree(fp);
}
-void bbc_envctrl_cleanup(void)
+void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
{
- struct bbc_cpu_temperature *tp;
- struct bbc_fan_control *fp;
+ struct bbc_cpu_temperature *tp, *tpos;
+ struct bbc_fan_control *fp, *fpos;
kthread_stop(kenvctrld_task);
- tp = all_bbc_temps;
- while (tp != NULL) {
- struct bbc_cpu_temperature *next = tp->next;
+ list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
+ list_del(&tp->bp_list);
+ list_del(&tp->glob_list);
destroy_one_temp(tp);
- tp = next;
}
- all_bbc_temps = NULL;
- fp = all_bbc_fans;
- while (fp != NULL) {
- struct bbc_fan_control *next = fp->next;
+ list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
+ list_del(&fp->bp_list);
+ list_del(&fp->glob_list);
destroy_one_fan(fp);
- fp = next;
}
- all_bbc_fans = NULL;
}
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index ac8ef2ce07f..f08e169ba1b 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -1,8 +1,7 @@
-/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $
- * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
+/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
* platforms.
*
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -14,9 +13,8 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <asm/oplib.h>
-#include <asm/ebus.h>
-#include <asm/spitfire.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/bbc.h>
#include <asm/io.h>
@@ -53,54 +51,12 @@
* The second controller also connects to the smartcard reader, if present.
*/
-#define NUM_CHILDREN 8
-struct bbc_i2c_bus {
- struct bbc_i2c_bus *next;
- int index;
- spinlock_t lock;
- void __iomem *i2c_bussel_reg;
- void __iomem *i2c_control_regs;
- unsigned char own, clock;
-
- wait_queue_head_t wq;
- volatile int waiting;
-
- struct linux_ebus_device *bus_edev;
- struct {
- struct linux_ebus_child *device;
- int client_claimed;
- } devs[NUM_CHILDREN];
-};
-
-static struct bbc_i2c_bus *all_bbc_i2c;
-
-struct bbc_i2c_client {
- struct bbc_i2c_bus *bp;
- struct linux_ebus_child *echild;
- int bus;
- int address;
-};
-
-static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild)
+static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val)
{
int i;
for (i = 0; i < NUM_CHILDREN; i++) {
- if (bp->devs[i].device == echild) {
- if (bp->devs[i].client_claimed)
- return 0;
- return 1;
- }
- }
- return 0;
-}
-
-static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val)
-{
- int i;
-
- for (i = 0; i < NUM_CHILDREN; i++) {
- if (bp->devs[i].device == echild) {
+ if (bp->devs[i].device == op) {
bp->devs[i].client_claimed = val;
return;
}
@@ -110,61 +66,47 @@ static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child
#define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1)
#define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0)
-static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild)
+struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
{
- struct bbc_i2c_bus *bp = all_bbc_i2c;
+ struct of_device *op = NULL;
+ int curidx = 0, i;
- while (bp != NULL) {
- if (find_device(bp, echild) != 0)
+ for (i = 0; i < NUM_CHILDREN; i++) {
+ if (!(op = bp->devs[i].device))
break;
- bp = bp->next;
+ if (curidx == index)
+ goto out;
+ op = NULL;
+ curidx++;
}
- return bp;
-}
-
-struct linux_ebus_child *bbc_i2c_getdev(int index)
-{
- struct bbc_i2c_bus *bp = all_bbc_i2c;
- struct linux_ebus_child *echild = NULL;
- int curidx = 0;
-
- while (bp != NULL) {
- struct bbc_i2c_bus *next = bp->next;
- int i;
-
- for (i = 0; i < NUM_CHILDREN; i++) {
- if (!(echild = bp->devs[i].device))
- break;
- if (curidx == index)
- goto out;
- echild = NULL;
- curidx++;
- }
- bp = next;
- }
out:
if (curidx == index)
- return echild;
+ return op;
return NULL;
}
-struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
+struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op)
{
- struct bbc_i2c_bus *bp = find_bus_for_device(echild);
struct bbc_i2c_client *client;
+ const u32 *reg;
- if (!bp)
- return NULL;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return NULL;
client->bp = bp;
- client->echild = echild;
- client->bus = echild->resource[0].start;
- client->address = echild->resource[1].start;
+ client->op = op;
+
+ reg = of_get_property(op->node, "reg", NULL);
+ if (!reg) {
+ kfree(client);
+ return NULL;
+ }
- claim_device(bp, echild);
+ client->bus = reg[0];
+ client->address = reg[1];
+
+ claim_device(bp, op);
return client;
}
@@ -172,9 +114,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
void bbc_i2c_detach(struct bbc_i2c_client *client)
{
struct bbc_i2c_bus *bp = client->bp;
- struct linux_ebus_child *echild = client->echild;
+ struct of_device *op = client->op;
- release_device(bp, echild);
+ release_device(bp, op);
kfree(client);
}
@@ -355,44 +297,43 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
}
-static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
+static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index)
{
struct bbc_i2c_bus *bp;
- struct linux_ebus_child *echild;
+ struct device_node *dp;
int entry;
bp = kzalloc(sizeof(*bp), GFP_KERNEL);
if (!bp)
- return -ENOMEM;
+ return NULL;
- bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
+ bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
if (!bp->i2c_control_regs)
goto fail;
- if (edev->num_addrs == 2) {
- bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1);
- if (!bp->i2c_bussel_reg)
- goto fail;
- }
+ bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
+ if (!bp->i2c_bussel_reg)
+ goto fail;
bp->waiting = 0;
init_waitqueue_head(&bp->wq);
- if (request_irq(edev->irqs[0], bbc_i2c_interrupt,
+ if (request_irq(op->irqs[0], bbc_i2c_interrupt,
IRQF_SHARED, "bbc_i2c", bp))
goto fail;
bp->index = index;
- bp->bus_edev = edev;
+ bp->op = op;
spin_lock_init(&bp->lock);
- bp->next = all_bbc_i2c;
- all_bbc_i2c = bp;
entry = 0;
- for (echild = edev->children;
- echild && entry < 8;
- echild = echild->next, entry++) {
- bp->devs[entry].device = echild;
+ for (dp = op->node->child;
+ dp && entry < 8;
+ dp = dp->sibling, entry++) {
+ struct of_device *child_op;
+
+ child_op = of_find_device_by_node(dp);
+ bp->devs[entry].device = child_op;
bp->devs[entry].client_claimed = 0;
}
@@ -406,86 +347,90 @@ static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
reset_one_i2c(bp);
- return 0;
+ return bp;
fail:
if (bp->i2c_bussel_reg)
- iounmap(bp->i2c_bussel_reg);
+ of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1);
if (bp->i2c_control_regs)
- iounmap(bp->i2c_control_regs);
+ of_iounmap(&op->resource[0], bp->i2c_control_regs, 2);
kfree(bp);
- return -EINVAL;
-}
-
-static int __init bbc_present(void)
-{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "bbc"))
- return 1;
- }
- }
- return 0;
+ return NULL;
}
-extern int bbc_envctrl_init(void);
-extern void bbc_envctrl_cleanup(void);
-static void bbc_i2c_cleanup(void);
+extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
+extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
-static int __init bbc_i2c_init(void)
+static int __devinit bbc_i2c_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
+ struct bbc_i2c_bus *bp;
int err, index = 0;
- if ((tlb_type != cheetah && tlb_type != cheetah_plus) ||
- !bbc_present())
- return -ENODEV;
+ bp = attach_one_i2c(op, index);
+ if (!bp)
+ return -EINVAL;
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "i2c")) {
- if (!attach_one_i2c(edev, index))
- index++;
- }
- }
+ err = bbc_envctrl_init(bp);
+ if (err) {
+ free_irq(op->irqs[0], bp);
+ if (bp->i2c_bussel_reg)
+ of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+ if (bp->i2c_control_regs)
+ of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
+ kfree(bp);
+ } else {
+ dev_set_drvdata(&op->dev, bp);
}
- if (!index)
- return -ENODEV;
-
- err = bbc_envctrl_init();
- if (err)
- bbc_i2c_cleanup();
return err;
}
-static void bbc_i2c_cleanup(void)
+static int __devexit bbc_i2c_remove(struct of_device *op)
{
- struct bbc_i2c_bus *bp = all_bbc_i2c;
+ struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
+
+ bbc_envctrl_cleanup(bp);
+
+ free_irq(op->irqs[0], bp);
- bbc_envctrl_cleanup();
+ if (bp->i2c_bussel_reg)
+ of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+ if (bp->i2c_control_regs)
+ of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
- while (bp != NULL) {
- struct bbc_i2c_bus *next = bp->next;
+ kfree(bp);
- free_irq(bp->bus_edev->irqs[0], bp);
+ return 0;
+}
- if (bp->i2c_bussel_reg)
- iounmap(bp->i2c_bussel_reg);
- if (bp->i2c_control_regs)
- iounmap(bp->i2c_control_regs);
+static const struct of_device_id bbc_i2c_match[] = {
+ {
+ .name = "i2c",
+ .compatible = "SUNW,bbc-i2c",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bbc_i2c_match);
- kfree(bp);
+static struct of_platform_driver bbc_i2c_driver = {
+ .name = "bbc_i2c",
+ .match_table = bbc_i2c_match,
+ .probe = bbc_i2c_probe,
+ .remove = __devexit_p(bbc_i2c_remove),
+};
- bp = next;
- }
- all_bbc_i2c = NULL;
+static int __init bbc_i2c_init(void)
+{
+ return of_register_driver(&bbc_i2c_driver, &of_bus_type);
+}
+
+static void __exit bbc_i2c_exit(void)
+{
+ of_unregister_driver(&bbc_i2c_driver);
}
module_init(bbc_i2c_init);
-module_exit(bbc_i2c_cleanup);
+module_exit(bbc_i2c_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h
index fb01bd17704..83c4811b7b5 100644
--- a/drivers/sbus/char/bbc_i2c.h
+++ b/drivers/sbus/char/bbc_i2c.h
@@ -1,14 +1,79 @@
-/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */
#ifndef _BBC_I2C_H
#define _BBC_I2C_H
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/list.h>
-struct bbc_i2c_client;
+struct bbc_i2c_client {
+ struct bbc_i2c_bus *bp;
+ struct of_device *op;
+ int bus;
+ int address;
+};
+
+enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
+
+struct bbc_cpu_temperature {
+ struct list_head bp_list;
+ struct list_head glob_list;
+
+ struct bbc_i2c_client *client;
+ int index;
+
+ /* Current readings, and history. */
+ s8 curr_cpu_temp;
+ s8 curr_amb_temp;
+ s8 prev_cpu_temp;
+ s8 prev_amb_temp;
+ s8 avg_cpu_temp;
+ s8 avg_amb_temp;
+
+ int sample_tick;
+
+ enum fan_action fan_todo[2];
+#define FAN_AMBIENT 0
+#define FAN_CPU 1
+};
+
+struct bbc_fan_control {
+ struct list_head bp_list;
+ struct list_head glob_list;
+
+ struct bbc_i2c_client *client;
+ int index;
+
+ int psupply_fan_on;
+ int cpu_fan_speed;
+ int system_fan_speed;
+};
+
+#define NUM_CHILDREN 8
+
+struct bbc_i2c_bus {
+ struct bbc_i2c_bus *next;
+ int index;
+ spinlock_t lock;
+ void __iomem *i2c_bussel_reg;
+ void __iomem *i2c_control_regs;
+ unsigned char own, clock;
+
+ wait_queue_head_t wq;
+ volatile int waiting;
+
+ struct list_head temps;
+ struct list_head fans;
+
+ struct of_device *op;
+ struct {
+ struct of_device *device;
+ int client_claimed;
+ } devs[NUM_CHILDREN];
+};
/* Probing and attachment. */
-extern struct linux_ebus_child *bbc_i2c_getdev(int);
-extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *);
+extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int);
+extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *);
extern void bbc_i2c_detach(struct bbc_i2c_client *);
/* Register read/write. NOTE: Blocking! */
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
deleted file mode 100644
index bba21e053a1..00000000000
--- a/drivers/sbus/char/bpp.c
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
- * drivers/sbus/char/bpp.c
- *
- * Copyright (c) 1995 Picture Elements
- * Stephen Williams (steve@icarus.com)
- * Gus Baldauf (gbaldauf@ix.netcom.com)
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#if defined(__i386__)
-# include <asm/system.h>
-#endif
-
-#if defined(__sparc__)
-# include <linux/init.h>
-# include <linux/delay.h> /* udelay() */
-
-# include <asm/oplib.h> /* OpenProm Library */
-# include <asm/sbus.h>
-#endif
-
-#include <asm/bpp.h>
-
-#define BPP_PROBE_CODE 0x55
-#define BPP_DELAY 100
-
-static const unsigned BPP_MAJOR = LP_MAJOR;
-static const char *bpp_dev_name = "bpp";
-
-/* When switching from compatibility to a mode where I can read, try
- the following mode first. */
-
-/* const unsigned char DEFAULT_ECP = 0x10; */
-static const unsigned char DEFAULT_ECP = 0x30;
-static const unsigned char DEFAULT_NIBBLE = 0x00;
-
-/*
- * These are 1284 time constraints, in units of jiffies.
- */
-
-static const unsigned long TIME_PSetup = 1;
-static const unsigned long TIME_PResponse = 6;
-static const unsigned long TIME_IDLE_LIMIT = 2000;
-
-/*
- * One instance per supported subdevice...
- */
-# define BPP_NO 3
-
-enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP };
-
-struct inst {
- unsigned present : 1; /* True if the hardware exists */
- unsigned enhanced : 1; /* True if the hardware in "enhanced" */
- unsigned opened : 1; /* True if the device is opened already */
- unsigned run_flag : 1; /* True if waiting for a repeate byte */
-
- unsigned char direction; /* 0 --> out, 0x20 --> IN */
- unsigned char pp_state; /* State of host controlled pins. */
- enum IEEE_Mode mode;
-
- unsigned char run_length;
- unsigned char repeat_byte;
-};
-
-static struct inst instances[BPP_NO];
-
-#if defined(__i386__)
-
-static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc };
-
-/*
- * These are for data access.
- * Control lines accesses are hidden in set_bits() and get_bits().
- * The exception is the probe procedure, which is system-dependent.
- */
-#define bpp_outb_p(data, base) outb_p((data), (base))
-#define bpp_inb(base) inb(base)
-#define bpp_inb_p(base) inb_p(base)
-
-/*
- * This method takes the pin values mask and sets the hardware pins to
- * the requested value: 1 == high voltage, 0 == low voltage. This
- * burries the annoying PC bit inversion and preserves the direction
- * flag.
- */
-static void set_pins(unsigned short pins, unsigned minor)
-{
- unsigned char bits = instances[minor].direction; /* == 0x20 */
-
- if (! (pins & BPP_PP_nStrobe)) bits |= 1;
- if (! (pins & BPP_PP_nAutoFd)) bits |= 2;
- if ( pins & BPP_PP_nInit) bits |= 4;
- if (! (pins & BPP_PP_nSelectIn)) bits |= 8;
-
- instances[minor].pp_state = bits;
-
- outb_p(bits, base_addrs[minor]+2);
-}
-
-static unsigned short get_pins(unsigned minor)
-{
- unsigned short bits = 0;
-
- unsigned value = instances[minor].pp_state;
- if (! (value & 0x01)) bits |= BPP_PP_nStrobe;
- if (! (value & 0x02)) bits |= BPP_PP_nAutoFd;
- if (value & 0x04) bits |= BPP_PP_nInit;
- if (! (value & 0x08)) bits |= BPP_PP_nSelectIn;
-
- value = inb_p(base_addrs[minor]+1);
- if (value & 0x08) bits |= BPP_GP_nFault;
- if (value & 0x10) bits |= BPP_GP_Select;
- if (value & 0x20) bits |= BPP_GP_PError;
- if (value & 0x40) bits |= BPP_GP_nAck;
- if (! (value & 0x80)) bits |= BPP_GP_Busy;
-
- return bits;
-}
-
-#endif /* __i386__ */
-
-#if defined(__sparc__)
-
-/*
- * Register block
- */
- /* DMA registers */
-#define BPP_CSR 0x00
-#define BPP_ADDR 0x04
-#define BPP_BCNT 0x08
-#define BPP_TST_CSR 0x0C
- /* Parallel Port registers */
-#define BPP_HCR 0x10
-#define BPP_OCR 0x12
-#define BPP_DR 0x14
-#define BPP_TCR 0x15
-#define BPP_OR 0x16
-#define BPP_IR 0x17
-#define BPP_ICR 0x18
-#define BPP_SIZE 0x1A
-
-/* BPP_CSR. Bits of type RW1 are cleared with writing '1'. */
-#define P_DEV_ID_MASK 0xf0000000 /* R */
-#define P_DEV_ID_ZEBRA 0x40000000
-#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */
-#define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */
-#define P_A_LOADED 0x04000000 /* R */
-#define P_DMA_ON 0x02000000 /* R DMA is not disabled */
-#define P_EN_NEXT 0x01000000 /* RW */
-#define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */
-#define P_DIAG 0x00100000 /* RW Disables draining and resetting
- of P-FIFO on loading of P_ADDR*/
-#define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */
-#define P_BURST_8 0x00000000
-#define P_BURST_4 0x00040000
-#define P_BURST_1 0x00080000 /* "No burst" write */
-#define P_TC 0x00004000 /* RW1 Term Count, can be cleared when
- P_EN_NEXT=1 */
-#define P_EN_CNT 0x00002000 /* RW */
-#define P_EN_DMA 0x00000200 /* RW */
-#define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */
-#define P_RESET 0x00000080 /* RW */
-#define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */
-#define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */
-#define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */
-#define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */
-#define P_ERR_PEND 0x00000002 /* R */
-#define P_INT_PEND 0x00000001 /* R */
-
-/* BPP_HCR. Time is in increments of SBus clock. */
-#define P_HCR_TEST 0x8000 /* Allows buried counters to be read */
-#define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */
-#define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) */
-
-/* BPP_OCR. */
-#define P_OCR_MEM_CLR 0x8000
-#define P_OCR_DATA_SRC 0x4000 /* ) */
-#define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */
-#define P_OCR_BUSY_DSEL 0x1000 /* ) selects */
-#define P_OCR_ACK_DSEL 0x0800 /* ) */
-#define P_OCR_EN_DIAG 0x0400
-#define P_OCR_BUSY_OP 0x0200 /* Busy operation */
-#define P_OCR_ACK_OP 0x0100 /* Ack operation */
-#define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */
-#define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */
-#define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */
-#define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. */
-
-/* BPP_TCR */
-#define P_TCR_DIR 0x08
-#define P_TCR_BUSY 0x04
-#define P_TCR_ACK 0x02
-#define P_TCR_DS 0x01 /* Strobe */
-
-/* BPP_OR */
-#define P_OR_V3 0x20 /* ) */
-#define P_OR_V2 0x10 /* ) on Zebra only */
-#define P_OR_V1 0x08 /* ) */
-#define P_OR_INIT 0x04
-#define P_OR_AFXN 0x02 /* Auto Feed */
-#define P_OR_SLCT_IN 0x01
-
-/* BPP_IR */
-#define P_IR_PE 0x04
-#define P_IR_SLCT 0x02
-#define P_IR_ERR 0x01
-
-/* BPP_ICR */
-#define P_DS_IRQ 0x8000 /* RW1 */
-#define P_ACK_IRQ 0x4000 /* RW1 */
-#define P_BUSY_IRQ 0x2000 /* RW1 */
-#define P_PE_IRQ 0x1000 /* RW1 */
-#define P_SLCT_IRQ 0x0800 /* RW1 */
-#define P_ERR_IRQ 0x0400 /* RW1 */
-#define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */
-#define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */
-#define P_BUSY_IRP 0x0080 /* RW 1= rising edge */
-#define P_BUSY_IRQ_EN 0x0040 /* RW */
-#define P_PE_IRP 0x0020 /* RW 1= rising edge */
-#define P_PE_IRQ_EN 0x0010 /* RW */
-#define P_SLCT_IRP 0x0008 /* RW 1= rising edge */
-#define P_SLCT_IRQ_EN 0x0004 /* RW */
-#define P_ERR_IRP 0x0002 /* RW1 1= rising edge */
-#define P_ERR_IRQ_EN 0x0001 /* RW */
-
-static void __iomem *base_addrs[BPP_NO];
-
-#define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR)
-#define bpp_inb_p(base) sbus_readb((base) + BPP_DR)
-#define bpp_inb(base) sbus_readb((base) + BPP_DR)
-
-static void set_pins(unsigned short pins, unsigned minor)
-{
- void __iomem *base = base_addrs[minor];
- unsigned char bits_tcr = 0, bits_or = 0;
-
- if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR;
- if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS;
-
- if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN;
- if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT;
- if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN;
-
- sbus_writeb(bits_or, base + BPP_OR);
- sbus_writeb(bits_tcr, base + BPP_TCR);
-}
-
-/*
- * i386 people read output pins from a software image.
- * We may get them back from hardware.
- * Again, inversion of pins must he buried here.
- */
-static unsigned short get_pins(unsigned minor)
-{
- void __iomem *base = base_addrs[minor];
- unsigned short bits = 0;
- unsigned value_tcr = sbus_readb(base + BPP_TCR);
- unsigned value_ir = sbus_readb(base + BPP_IR);
- unsigned value_or = sbus_readb(base + BPP_OR);
-
- if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe;
- if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd;
- if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit;
- if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn;
-
- if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault;
- if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select;
- if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError;
- if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck;
- if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy;
-
- return bits;
-}
-
-#endif /* __sparc__ */
-
-static void snooze(unsigned long snooze_time, unsigned minor)
-{
- schedule_timeout_uninterruptible(snooze_time + 1);
-}
-
-static int wait_for(unsigned short set, unsigned short clr,
- unsigned long delay, unsigned minor)
-{
- unsigned short pins = get_pins(minor);
-
- unsigned long extime = 0;
-
- /*
- * Try a real fast scan for the first jiffy, in case the device
- * responds real good. The first while loop guesses an expire
- * time accounting for possible wraparound of jiffies.
- */
- while (time_after_eq(jiffies, extime)) extime = jiffies + 1;
- while ( (time_before(jiffies, extime))
- && (((pins & set) != set) || ((pins & clr) != 0)) ) {
- pins = get_pins(minor);
- }
-
- delay -= 1;
-
- /*
- * If my delay expired or the pins are still not where I want
- * them, then resort to using the timer and greatly reduce my
- * sample rate. If the peripheral is going to be slow, this will
- * give the CPU up to some more worthy process.
- */
- while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) {
-
- snooze(1, minor);
- pins = get_pins(minor);
- delay -= 1;
- }
-
- if (delay == 0) return -1;
- else return pins;
-}
-
-/*
- * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An
- * errno means something broke, and I do not yet know how to fix it.
- */
-static int negotiate(unsigned char mode, unsigned minor)
-{
- int rc;
- unsigned short pins = get_pins(minor);
- if (pins & BPP_PP_nSelectIn) return -EIO;
-
-
- /* Event 0: Write the mode to the data lines */
- bpp_outb_p(mode, base_addrs[minor]);
-
- snooze(TIME_PSetup, minor);
-
- /* Event 1: Strobe the mode code into the peripheral */
- set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
- /* Wait for Event 2: Peripheral responds as a 1284 device. */
- rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault,
- BPP_GP_nAck,
- TIME_PResponse,
- minor);
-
- if (rc == -1) return -ETIMEDOUT;
-
- /* Event 3: latch extensibility request */
- set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor);
-
- /* ... quick nap while peripheral ponders the byte i'm sending...*/
- snooze(1, minor);
-
- /* Event 4: restore strobe, to ACK peripheral's response. */
- set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
- /* Wait for Event 6: Peripheral latches response bits */
- rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor);
- if (rc == -1) return -EIO;
-
- /* A 1284 device cannot refuse nibble mode */
- if (mode == DEFAULT_NIBBLE) return 0;
-
- if (pins & BPP_GP_Select) return 0;
-
- return -EPROTONOSUPPORT;
-}
-
-static int terminate(unsigned minor)
-{
- int rc;
-
- /* Event 22: Request termination of 1284 mode */
- set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
- /* Wait for Events 23 and 24: ACK termination request. */
- rc = wait_for(BPP_GP_Busy|BPP_GP_nFault,
- BPP_GP_nAck,
- TIME_PSetup+TIME_PResponse,
- minor);
-
- instances[minor].direction = 0;
- instances[minor].mode = COMPATIBILITY;
-
- if (rc == -1) {
- return -EIO;
- }
-
- /* Event 25: Handshake by lowering nAutoFd */
- set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
- /* Event 26: Peripheral wiggles lines... */
-
- /* Event 27: Peripheral sets nAck HIGH to ack handshake */
- rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
- if (rc == -1) {
- set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
- return -EIO;
- }
-
- /* Event 28: Finish phase by raising nAutoFd */
- set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
- return 0;
-}
-
-static DEFINE_SPINLOCK(bpp_open_lock);
-
-/*
- * Allow only one process to open the device at a time.
- */
-static int bpp_open(struct inode *inode, struct file *f)
-{
- unsigned minor = iminor(inode);
- int ret;
-
- lock_kernel();
- spin_lock(&bpp_open_lock);
- ret = 0;
- if (minor >= BPP_NO) {
- ret = -ENODEV;
- } else {
- if (! instances[minor].present) {
- ret = -ENODEV;
- } else {
- if (instances[minor].opened)
- ret = -EBUSY;
- else
- instances[minor].opened = 1;
- }
- }
- spin_unlock(&bpp_open_lock);
- unlock_kernel();
-
- return ret;
-}
-
-/*
- * When the process closes the device, this method is called to clean
- * up and reset the hardware. Always leave the device in compatibility
- * mode as this is a reasonable place to clean up from messes made by
- * ioctls, or other mayhem.
- */
-static int bpp_release(struct inode *inode, struct file *f)
-{
- unsigned minor = iminor(inode);
-
- spin_lock(&bpp_open_lock);
- instances[minor].opened = 0;
-
- if (instances[minor].mode != COMPATIBILITY)
- terminate(minor);
-
- spin_unlock(&bpp_open_lock);
-
- return 0;
-}
-
-static long read_nibble(unsigned minor, char __user *c, unsigned long cnt)
-{
- unsigned long remaining = cnt;
- long rc;
-
- while (remaining > 0) {
- unsigned char byte = 0;
- int pins;
-
- /* Event 7: request nibble */
- set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
- /* Wait for event 9: Peripher strobes first nibble */
- pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
- if (pins == -1) return -ETIMEDOUT;
-
- /* Event 10: I handshake nibble */
- set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
- if (pins & BPP_GP_nFault) byte |= 0x01;
- if (pins & BPP_GP_Select) byte |= 0x02;
- if (pins & BPP_GP_PError) byte |= 0x04;
- if (pins & BPP_GP_Busy) byte |= 0x08;
-
- /* Wait for event 11: Peripheral handshakes nibble */
- rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-
- /* Event 7: request nibble */
- set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
- /* Wait for event 9: Peripher strobes first nibble */
- pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor);
- if (rc == -1) return -ETIMEDOUT;
-
- /* Event 10: I handshake nibble */
- set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
- if (pins & BPP_GP_nFault) byte |= 0x10;
- if (pins & BPP_GP_Select) byte |= 0x20;
- if (pins & BPP_GP_PError) byte |= 0x40;
- if (pins & BPP_GP_Busy) byte |= 0x80;
-
- if (put_user(byte, c))
- return -EFAULT;
- c += 1;
- remaining -= 1;
-
- /* Wait for event 11: Peripheral handshakes nibble */
- rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
- if (rc == -1) return -EIO;
- }
-
- return cnt - remaining;
-}
-
-static long read_ecp(unsigned minor, char __user *c, unsigned long cnt)
-{
- unsigned long remaining;
- long rc;
-
- /* Turn ECP mode from forward to reverse if needed. */
- if (! instances[minor].direction) {
- unsigned short pins = get_pins(minor);
-
- /* Event 38: Turn the bus around */
- instances[minor].direction = 0x20;
- pins &= ~BPP_PP_nAutoFd;
- set_pins(pins, minor);
-
- /* Event 39: Set pins for reverse mode. */
- snooze(TIME_PSetup, minor);
- set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
- /* Wait for event 40: Peripheral ready to be strobed */
- rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor);
- if (rc == -1) return -ETIMEDOUT;
- }
-
- remaining = cnt;
-
- while (remaining > 0) {
-
- /* If there is a run length for a repeated byte, repeat */
- /* that byte a few times. */
- if (instances[minor].run_length && !instances[minor].run_flag) {
-
- char buffer[128];
- unsigned idx;
- unsigned repeat = remaining < instances[minor].run_length
- ? remaining
- : instances[minor].run_length;
-
- for (idx = 0 ; idx < repeat ; idx += 1)
- buffer[idx] = instances[minor].repeat_byte;
-
- if (copy_to_user(c, buffer, repeat))
- return -EFAULT;
- remaining -= repeat;
- c += repeat;
- instances[minor].run_length -= repeat;
- }
-
- if (remaining == 0) break;
-
-
- /* Wait for Event 43: Data active on the bus. */
- rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
- if (rc == -1) break;
-
- if (rc & BPP_GP_Busy) {
- /* OK, this is data. read it in. */
- unsigned char byte = bpp_inb(base_addrs[minor]);
- if (put_user(byte, c))
- return -EFAULT;
- c += 1;
- remaining -= 1;
-
- if (instances[minor].run_flag) {
- instances[minor].repeat_byte = byte;
- instances[minor].run_flag = 0;
- }
-
- } else {
- unsigned char byte = bpp_inb(base_addrs[minor]);
- if (byte & 0x80) {
- printk("bpp%d: "
- "Ignoring ECP channel %u from device.\n",
- minor, byte & 0x7f);
- } else {
- instances[minor].run_length = byte;
- instances[minor].run_flag = 1;
- }
- }
-
- /* Event 44: I got it. */
- set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor);
-
- /* Wait for event 45: peripheral handshake */
- rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
- if (rc == -1) return -ETIMEDOUT;
-
- /* Event 46: Finish handshake */
- set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
- }
-
-
- return cnt - remaining;
-}
-
-static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos)
-{
- long rc;
- unsigned minor = iminor(f->f_path.dentry->d_inode);
- if (minor >= BPP_NO) return -ENODEV;
- if (!instances[minor].present) return -ENODEV;
-
- switch (instances[minor].mode) {
-
- default:
- if (instances[minor].mode != COMPATIBILITY)
- terminate(minor);
-
- if (instances[minor].enhanced) {
- /* For now, do all reads with ECP-RLE mode */
- unsigned short pins;
-
- rc = negotiate(DEFAULT_ECP, minor);
- if (rc < 0) break;
-
- instances[minor].mode = ECP_RLE;
-
- /* Event 30: set nAutoFd low to setup for ECP mode */
- pins = get_pins(minor);
- pins &= ~BPP_PP_nAutoFd;
- set_pins(pins, minor);
-
- /* Wait for Event 31: peripheral ready */
- rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
- if (rc == -1) return -ETIMEDOUT;
-
- rc = read_ecp(minor, c, cnt);
-
- } else {
- rc = negotiate(DEFAULT_NIBBLE, minor);
- if (rc < 0) break;
-
- instances[minor].mode = NIBBLE;
-
- rc = read_nibble(minor, c, cnt);
- }
- break;
-
- case NIBBLE:
- rc = read_nibble(minor, c, cnt);
- break;
-
- case ECP:
- case ECP_RLE:
- rc = read_ecp(minor, c, cnt);
- break;
-
- }
-
-
- return rc;
-}
-
-/*
- * Compatibility mode handshaking is a matter of writing data,
- * strobing it, and waiting for the printer to stop being busy.
- */
-static long write_compat(unsigned minor, const char __user *c, unsigned long cnt)
-{
- long rc;
- unsigned short pins = get_pins(minor);
-
- unsigned long remaining = cnt;
-
-
- while (remaining > 0) {
- unsigned char byte;
-
- if (get_user(byte, c))
- return -EFAULT;
- c += 1;
-
- rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor);
- if (rc == -1) return -ETIMEDOUT;
-
- bpp_outb_p(byte, base_addrs[minor]);
- remaining -= 1;
- /* snooze(1, minor); */
-
- pins &= ~BPP_PP_nStrobe;
- set_pins(pins, minor);
-
- rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
-
- pins |= BPP_PP_nStrobe;
- set_pins(pins, minor);
- }
-
- return cnt - remaining;
-}
-
-/*
- * Write data using ECP mode. Watch out that the port may be set up
- * for reading. If so, turn the port around.
- */
-static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt)
-{
- unsigned short pins = get_pins(minor);
- unsigned long remaining = cnt;
-
- if (instances[minor].direction) {
- int rc;
-
- /* Event 47 Request bus be turned around */
- pins |= BPP_PP_nInit;
- set_pins(pins, minor);
-
- /* Wait for Event 49: Peripheral relinquished bus */
- rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
-
- pins |= BPP_PP_nAutoFd;
- instances[minor].direction = 0;
- set_pins(pins, minor);
- }
-
- while (remaining > 0) {
- unsigned char byte;
- int rc;
-
- if (get_user(byte, c))
- return -EFAULT;
-
- rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor);
- if (rc == -1) return -ETIMEDOUT;
-
- c += 1;
-
- bpp_outb_p(byte, base_addrs[minor]);
-
- pins &= ~BPP_PP_nStrobe;
- set_pins(pins, minor);
-
- pins |= BPP_PP_nStrobe;
- rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
- if (rc == -1) return -EIO;
-
- set_pins(pins, minor);
- }
-
- return cnt - remaining;
-}
-
-/*
- * Write to the peripheral. Be sensitive of the current mode. If I'm
- * in a mode that can be turned around (ECP) then just do
- * that. Otherwise, terminate and do my writing in compat mode. This
- * is the safest course as any device can handle it.
- */
-static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos)
-{
- long errno = 0;
- unsigned minor = iminor(f->f_path.dentry->d_inode);
- if (minor >= BPP_NO) return -ENODEV;
- if (!instances[minor].present) return -ENODEV;
-
- switch (instances[minor].mode) {
-
- case ECP:
- case ECP_RLE:
- errno = write_ecp(minor, c, cnt);
- break;
- case COMPATIBILITY:
- errno = write_compat(minor, c, cnt);
- break;
- default:
- terminate(minor);
- errno = write_compat(minor, c, cnt);
- }
-
- return errno;
-}
-
-static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd,
- unsigned long arg)
-{
- int errno = 0;
-
- unsigned minor = iminor(inode);
- if (minor >= BPP_NO) return -ENODEV;
- if (!instances[minor].present) return -ENODEV;
-
-
- switch (cmd) {
-
- case BPP_PUT_PINS:
- set_pins(arg, minor);
- break;
-
- case BPP_GET_PINS:
- errno = get_pins(minor);
- break;
-
- case BPP_PUT_DATA:
- bpp_outb_p(arg, base_addrs[minor]);
- break;
-
- case BPP_GET_DATA:
- errno = bpp_inb_p(base_addrs[minor]);
- break;
-
- case BPP_SET_INPUT:
- if (arg)
- if (instances[minor].enhanced) {
- unsigned short bits = get_pins(minor);
- instances[minor].direction = 0x20;
- set_pins(bits, minor);
- } else {
- errno = -ENOTTY;
- }
- else {
- unsigned short bits = get_pins(minor);
- instances[minor].direction = 0x00;
- set_pins(bits, minor);
- }
- break;
-
- default:
- errno = -EINVAL;
- }
-
- return errno;
-}
-
-static const struct file_operations bpp_fops = {
- .owner = THIS_MODULE,
- .read = bpp_read,
- .write = bpp_write,
- .ioctl = bpp_ioctl,
- .open = bpp_open,
- .release = bpp_release,
-};
-
-#if defined(__i386__)
-
-#define collectLptPorts() {}
-
-static void probeLptPort(unsigned idx)
-{
- unsigned int testvalue;
- const unsigned short lpAddr = base_addrs[idx];
-
- instances[idx].present = 0;
- instances[idx].enhanced = 0;
- instances[idx].direction = 0;
- instances[idx].mode = COMPATIBILITY;
- instances[idx].run_length = 0;
- instances[idx].run_flag = 0;
- if (!request_region(lpAddr,3, bpp_dev_name)) return;
-
- /*
- * First, make sure the instance exists. Do this by writing to
- * the data latch and reading the value back. If the port *is*
- * present, test to see if it supports extended-mode
- * operation. This will be required for IEEE1284 reverse
- * transfers.
- */
-
- outb_p(BPP_PROBE_CODE, lpAddr);
- for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
- ;
- testvalue = inb_p(lpAddr);
- if (testvalue == BPP_PROBE_CODE) {
- unsigned save;
- instances[idx].present = 1;
-
- save = inb_p(lpAddr+2);
- for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
- ;
- outb_p(save|0x20, lpAddr+2);
- for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
- ;
- outb_p(~BPP_PROBE_CODE, lpAddr);
- for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
- ;
- testvalue = inb_p(lpAddr);
- if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE))
- instances[idx].enhanced = 0;
- else
- instances[idx].enhanced = 1;
- outb_p(save, lpAddr+2);
- }
- else {
- release_region(lpAddr,3);
- }
- /*
- * Leave the port in compat idle mode.
- */
- set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
- printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx],
- instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE");
-}
-
-static inline void freeLptPort(int idx)
-{
- release_region(base_addrs[idx], 3);
-}
-
-#endif
-
-#if defined(__sparc__)
-
-static void __iomem *map_bpp(struct sbus_dev *dev, int idx)
-{
- return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp");
-}
-
-static int collectLptPorts(void)
-{
- struct sbus_bus *bus;
- struct sbus_dev *dev;
- int count;
-
- count = 0;
- for_all_sbusdev(dev, bus) {
- if (strcmp(dev->prom_name, "SUNW,bpp") == 0) {
- if (count >= BPP_NO) {
- printk(KERN_NOTICE
- "bpp: More than %d bpp ports,"
- " rest is ignored\n", BPP_NO);
- return count;
- }
- base_addrs[count] = map_bpp(dev, count);
- count++;
- }
- }
- return count;
-}
-
-static void probeLptPort(unsigned idx)
-{
- void __iomem *rp = base_addrs[idx];
- __u32 csr;
- char *brand;
-
- instances[idx].present = 0;
- instances[idx].enhanced = 0;
- instances[idx].direction = 0;
- instances[idx].mode = COMPATIBILITY;
- instances[idx].run_length = 0;
- instances[idx].run_flag = 0;
-
- if (!rp) return;
-
- instances[idx].present = 1;
- instances[idx].enhanced = 1; /* Sure */
-
- csr = sbus_readl(rp + BPP_CSR);
- if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
- udelay(20);
- csr = sbus_readl(rp + BPP_CSR);
- if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
- printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr);
- }
- }
- printk("bpp%d: reset with 0x%08x ..", idx, csr);
- sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR);
- udelay(500);
- sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR);
- csr = sbus_readl(rp + BPP_CSR);
- printk(" done with csr=0x%08x ocr=0x%04x\n",
- csr, sbus_readw(rp + BPP_OCR));
-
- switch (csr & P_DEV_ID_MASK) {
- case P_DEV_ID_ZEBRA:
- brand = "Zebra";
- break;
- case P_DEV_ID_L64854:
- brand = "DMA2";
- break;
- default:
- brand = "Unknown";
- }
- printk("bpp%d: %s at %p\n", idx, brand, rp);
-
- /*
- * Leave the port in compat idle mode.
- */
- set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
- return;
-}
-
-static inline void freeLptPort(int idx)
-{
- sbus_iounmap(base_addrs[idx], BPP_SIZE);
-}
-
-#endif
-
-static int __init bpp_init(void)
-{
- int rc;
- unsigned idx;
-
- rc = collectLptPorts();
- if (rc == 0)
- return -ENODEV;
-
- rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops);
- if (rc < 0)
- return rc;
-
- for (idx = 0; idx < BPP_NO; idx++) {
- instances[idx].opened = 0;
- probeLptPort(idx);
- }
-
- return 0;
-}
-
-static void __exit bpp_cleanup(void)
-{
- unsigned idx;
-
- unregister_chrdev(BPP_MAJOR, bpp_dev_name);
-
- for (idx = 0; idx < BPP_NO; idx++) {
- if (instances[idx].present)
- freeLptPort(idx);
- }
-}
-
-module_init(bpp_init);
-module_exit(bpp_cleanup);
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
deleted file mode 100644
index 23abfdfb44f..00000000000
--- a/drivers/sbus/char/cpwatchdog.c
+++ /dev/null
@@ -1,858 +0,0 @@
-/* cpwatchdog.c - driver implementation for hardware watchdog
- * timers found on Sun Microsystems CP1400 and CP1500 boards.
- *
- * This device supports both the generic Linux watchdog
- * interface and Solaris-compatible ioctls as best it is
- * able.
- *
- * NOTE: CP1400 systems appear to have a defective intr_mask
- * register on the PLD, preventing the disabling of
- * timer interrupts. We use a timer to periodically
- * reset 'stopped' watchdogs on affected platforms.
- *
- * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/major.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/smp_lock.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-
-#include <asm/watchdog.h>
-
-#define WD_OBPNAME "watchdog"
-#define WD_BADMODEL "SUNW,501-5336"
-#define WD_BTIMEOUT (jiffies + (HZ * 1000))
-#define WD_BLIMIT 0xFFFF
-
-#define WD0_DEVNAME "watchdog0"
-#define WD1_DEVNAME "watchdog1"
-#define WD2_DEVNAME "watchdog2"
-
-#define WD0_MINOR 212
-#define WD1_MINOR 213
-#define WD2_MINOR 214
-
-
-/* Internal driver definitions
- */
-#define WD0_ID 0 /* Watchdog0 */
-#define WD1_ID 1 /* Watchdog1 */
-#define WD2_ID 2 /* Watchdog2 */
-#define WD_NUMDEVS 3 /* Device contains 3 timers */
-
-#define WD_INTR_OFF 0 /* Interrupt disable value */
-#define WD_INTR_ON 1 /* Interrupt enable value */
-
-#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */
-#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */
-#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */
-
-/* Register value definitions
- */
-#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */
-#define WD1_INTR_MASK 0x02
-#define WD2_INTR_MASK 0x04
-
-#define WD_S_RUNNING 0x01 /* Watchdog device status running */
-#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */
-
-/* Sun uses Altera PLD EPF8820ATC144-4
- * providing three hardware watchdogs:
- *
- * 1) RIC - sends an interrupt when triggered
- * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU
- * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
- *
- *** Timer register block definition (struct wd_timer_regblk)
- *
- * dcntr and limit registers (halfword access):
- * -------------------
- * | 15 | ...| 1 | 0 |
- * -------------------
- * |- counter val -|
- * -------------------
- * dcntr - Current 16-bit downcounter value.
- * When downcounter reaches '0' watchdog expires.
- * Reading this register resets downcounter with 'limit' value.
- * limit - 16-bit countdown value in 1/10th second increments.
- * Writing this register begins countdown with input value.
- * Reading from this register does not affect counter.
- * NOTES: After watchdog reset, dcntr and limit contain '1'
- *
- * status register (byte access):
- * ---------------------------
- * | 7 | ... | 2 | 1 | 0 |
- * --------------+------------
- * |- UNUSED -| EXP | RUN |
- * ---------------------------
- * status- Bit 0 - Watchdog is running
- * Bit 1 - Watchdog has expired
- *
- *** PLD register block definition (struct wd_pld_regblk)
- *
- * intr_mask register (byte access):
- * ---------------------------------
- * | 7 | ... | 3 | 2 | 1 | 0 |
- * +-------------+------------------
- * |- UNUSED -| WD3 | WD2 | WD1 |
- * ---------------------------------
- * WD3 - 1 == Interrupt disabled for watchdog 3
- * WD2 - 1 == Interrupt disabled for watchdog 2
- * WD1 - 1 == Interrupt disabled for watchdog 1
- *
- * pld_status register (byte access):
- * UNKNOWN, MAGICAL MYSTERY REGISTER
- *
- */
-#define WD_TIMER_REGSZ 16
-#define WD0_OFF 0
-#define WD1_OFF (WD_TIMER_REGSZ * 1)
-#define WD2_OFF (WD_TIMER_REGSZ * 2)
-#define PLD_OFF (WD_TIMER_REGSZ * 3)
-
-#define WD_DCNTR 0x00
-#define WD_LIMIT 0x04
-#define WD_STATUS 0x08
-
-#define PLD_IMASK (PLD_OFF + 0x00)
-#define PLD_STATUS (PLD_OFF + 0x04)
-
-/* Individual timer structure
- */
-struct wd_timer {
- __u16 timeout;
- __u8 intr_mask;
- unsigned char runstatus;
- void __iomem *regs;
-};
-
-/* Device structure
- */
-struct wd_device {
- int irq;
- spinlock_t lock;
- unsigned char isbaddoggie; /* defective PLD */
- unsigned char opt_enable;
- unsigned char opt_reboot;
- unsigned short opt_timeout;
- unsigned char initialized;
- struct wd_timer watchdog[WD_NUMDEVS];
- void __iomem *regs;
-};
-
-static struct wd_device wd_dev = {
- 0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0,
-};
-
-static struct timer_list wd_timer;
-
-static int wd0_timeout = 0;
-static int wd1_timeout = 0;
-static int wd2_timeout = 0;
-
-#ifdef MODULE
-module_param (wd0_timeout, int, 0);
-MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
-module_param (wd1_timeout, int, 0);
-MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
-module_param (wd2_timeout, int, 0);
-MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
-
-MODULE_AUTHOR
- ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
- ("Hardware watchdog driver for Sun Microsystems CP1400/1500");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
- ("watchdog");
-#endif /* ifdef MODULE */
-
-/* Forward declarations of internal methods
- */
-#ifdef WD_DEBUG
-static void wd_dumpregs(void);
-#endif
-static irqreturn_t wd_interrupt(int irq, void *dev_id);
-static void wd_toggleintr(struct wd_timer* pTimer, int enable);
-static void wd_pingtimer(struct wd_timer* pTimer);
-static void wd_starttimer(struct wd_timer* pTimer);
-static void wd_resetbrokentimer(struct wd_timer* pTimer);
-static void wd_stoptimer(struct wd_timer* pTimer);
-static void wd_brokentimer(unsigned long data);
-static int wd_getstatus(struct wd_timer* pTimer);
-
-/* PLD expects words to be written in LSB format,
- * so we must flip all words prior to writing them to regs
- */
-static inline unsigned short flip_word(unsigned short word)
-{
- return ((word & 0xff) << 8) | ((word >> 8) & 0xff);
-}
-
-#define wd_writew(val, addr) (writew(flip_word(val), addr))
-#define wd_readw(addr) (flip_word(readw(addr)))
-#define wd_writeb(val, addr) (writeb(val, addr))
-#define wd_readb(addr) (readb(addr))
-
-
-/* CP1400s seem to have broken PLD implementations--
- * the interrupt_mask register cannot be written, so
- * no timer interrupts can be masked within the PLD.
- */
-static inline int wd_isbroken(void)
-{
- /* we could test this by read/write/read/restore
- * on the interrupt mask register only if OBP
- * 'watchdog-enable?' == FALSE, but it seems
- * ubiquitous on CP1400s
- */
- char val[32];
- prom_getproperty(prom_root_node, "model", val, sizeof(val));
- return((!strcmp(val, WD_BADMODEL)) ? 1 : 0);
-}
-
-/* Retrieve watchdog-enable? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_enable(void)
-{
- int opt_node;
-
- opt_node = prom_getchild(prom_root_node);
- opt_node = prom_searchsiblings(opt_node, "options");
- return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-reboot? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_reboot(void)
-{
- int opt_node;
-
- opt_node = prom_getchild(prom_root_node);
- opt_node = prom_searchsiblings(opt_node, "options");
- return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-timeout option from OBP
- * Returns OBP value, or 0 if not located
- */
-static inline int wd_opt_timeout(void)
-{
- int opt_node;
- char value[32];
- char *p = value;
-
- opt_node = prom_getchild(prom_root_node);
- opt_node = prom_searchsiblings(opt_node, "options");
- opt_node = prom_getproperty(opt_node,
- "watchdog-timeout",
- value,
- sizeof(value));
- if(-1 != opt_node) {
- /* atoi implementation */
- for(opt_node = 0; /* nop */; p++) {
- if(*p >= '0' && *p <= '9') {
- opt_node = (10*opt_node)+(*p-'0');
- }
- else {
- break;
- }
- }
- }
- return((-1 == opt_node) ? (0) : (opt_node));
-}
-
-static int wd_open(struct inode *inode, struct file *f)
-{
- lock_kernel();
- switch(iminor(inode))
- {
- case WD0_MINOR:
- f->private_data = &wd_dev.watchdog[WD0_ID];
- break;
- case WD1_MINOR:
- f->private_data = &wd_dev.watchdog[WD1_ID];
- break;
- case WD2_MINOR:
- f->private_data = &wd_dev.watchdog[WD2_ID];
- break;
- default:
- unlock_kernel();
- return(-ENODEV);
- }
-
- /* Register IRQ on first open of device */
- if(0 == wd_dev.initialized)
- {
- if (request_irq(wd_dev.irq,
- &wd_interrupt,
- IRQF_SHARED,
- WD_OBPNAME,
- (void *)wd_dev.regs)) {
- printk("%s: Cannot register IRQ %d\n",
- WD_OBPNAME, wd_dev.irq);
- unlock_kernel();
- return(-EBUSY);
- }
- wd_dev.initialized = 1;
- }
-
- unlock_kernel();
- return(nonseekable_open(inode, f));
-}
-
-static int wd_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int wd_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int setopt = 0;
- struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
- void __user *argp = (void __user *)arg;
- struct watchdog_info info = {
- 0,
- 0,
- "Altera EPF8820ATC144-4"
- };
-
- if(NULL == pTimer) {
- return(-EINVAL);
- }
-
- switch(cmd)
- {
- /* Generic Linux IOCTLs */
- case WDIOC_GETSUPPORT:
- if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) {
- return(-EFAULT);
- }
- break;
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- if (put_user(0, (int __user *)argp))
- return -EFAULT;
- break;
- case WDIOC_KEEPALIVE:
- wd_pingtimer(pTimer);
- break;
- case WDIOC_SETOPTIONS:
- if(copy_from_user(&setopt, argp, sizeof(unsigned int))) {
- return -EFAULT;
- }
- if(setopt & WDIOS_DISABLECARD) {
- if(wd_dev.opt_enable) {
- printk(
- "%s: cannot disable watchdog in ENABLED mode\n",
- WD_OBPNAME);
- return(-EINVAL);
- }
- wd_stoptimer(pTimer);
- }
- else if(setopt & WDIOS_ENABLECARD) {
- wd_starttimer(pTimer);
- }
- else {
- return(-EINVAL);
- }
- break;
- /* Solaris-compatible IOCTLs */
- case WIOCGSTAT:
- setopt = wd_getstatus(pTimer);
- if(copy_to_user(argp, &setopt, sizeof(unsigned int))) {
- return(-EFAULT);
- }
- break;
- case WIOCSTART:
- wd_starttimer(pTimer);
- break;
- case WIOCSTOP:
- if(wd_dev.opt_enable) {
- printk("%s: cannot disable watchdog in ENABLED mode\n",
- WD_OBPNAME);
- return(-EINVAL);
- }
- wd_stoptimer(pTimer);
- break;
- default:
- return(-EINVAL);
- }
- return(0);
-}
-
-static long wd_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int rval = -ENOIOCTLCMD;
-
- switch (cmd) {
- /* solaris ioctls are specific to this driver */
- case WIOCSTART:
- case WIOCSTOP:
- case WIOCGSTAT:
- lock_kernel();
- rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
- unlock_kernel();
- break;
- /* everything else is handled by the generic compat layer */
- default:
- break;
- }
-
- return rval;
-}
-
-static ssize_t wd_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
-
- if(NULL == pTimer) {
- return(-EINVAL);
- }
-
- if (count) {
- wd_pingtimer(pTimer);
- return 1;
- }
- return 0;
-}
-
-static ssize_t wd_read(struct file * file, char __user *buffer,
- size_t count, loff_t *ppos)
-{
-#ifdef WD_DEBUG
- wd_dumpregs();
- return(0);
-#else
- return(-EINVAL);
-#endif /* ifdef WD_DEBUG */
-}
-
-static irqreturn_t wd_interrupt(int irq, void *dev_id)
-{
- /* Only WD0 will interrupt-- others are NMI and we won't
- * see them here....
- */
- spin_lock_irq(&wd_dev.lock);
- if((unsigned long)wd_dev.regs == (unsigned long)dev_id)
- {
- wd_stoptimer(&wd_dev.watchdog[WD0_ID]);
- wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD;
- }
- spin_unlock_irq(&wd_dev.lock);
- return IRQ_HANDLED;
-}
-
-static const struct file_operations wd_fops = {
- .owner = THIS_MODULE,
- .ioctl = wd_ioctl,
- .compat_ioctl = wd_compat_ioctl,
- .open = wd_open,
- .write = wd_write,
- .read = wd_read,
- .release = wd_release,
-};
-
-static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops };
-static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops };
-static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops };
-
-#ifdef WD_DEBUG
-static void wd_dumpregs(void)
-{
- /* Reading from downcounters initiates watchdog countdown--
- * Example is included below for illustration purposes.
- */
- int i;
- printk("%s: dumping register values\n", WD_OBPNAME);
- for(i = WD0_ID; i < WD_NUMDEVS; ++i) {
- /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n",
- * WD_OBPNAME,
- * i,
- * (unsigned long)(&wd_dev.watchdog[i].regs->dcntr),
- * readw(&wd_dev.watchdog[i].regs->dcntr));
- */
- printk("\t%s%i: limit at 0x%lx: 0x%x\n",
- WD_OBPNAME,
- i,
- (unsigned long)(&wd_dev.watchdog[i].regs->limit),
- readw(&wd_dev.watchdog[i].regs->limit));
- printk("\t%s%i: status at 0x%lx: 0x%x\n",
- WD_OBPNAME,
- i,
- (unsigned long)(&wd_dev.watchdog[i].regs->status),
- readb(&wd_dev.watchdog[i].regs->status));
- printk("\t%s%i: driver status: 0x%x\n",
- WD_OBPNAME,
- i,
- wd_getstatus(&wd_dev.watchdog[i]));
- }
- printk("\tintr_mask at %p: 0x%x\n",
- wd_dev.regs + PLD_IMASK,
- readb(wd_dev.regs + PLD_IMASK));
- printk("\tpld_status at %p: 0x%x\n",
- wd_dev.regs + PLD_STATUS,
- readb(wd_dev.regs + PLD_STATUS));
-}
-#endif
-
-/* Enable or disable watchdog interrupts
- * Because of the CP1400 defect this should only be
- * called during initialzation or by wd_[start|stop]timer()
- *
- * pTimer - pointer to timer device, or NULL to indicate all timers
- * enable - non-zero to enable interrupts, zero to disable
- */
-static void wd_toggleintr(struct wd_timer* pTimer, int enable)
-{
- unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK);
- unsigned char setregs =
- (NULL == pTimer) ?
- (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) :
- (pTimer->intr_mask);
-
- (WD_INTR_ON == enable) ?
- (curregs &= ~setregs):
- (curregs |= setregs);
-
- wd_writeb(curregs, wd_dev.regs + PLD_IMASK);
- return;
-}
-
-/* Reset countdown timer with 'limit' value and continue countdown.
- * This will not start a stopped timer.
- *
- * pTimer - pointer to timer device
- */
-static void wd_pingtimer(struct wd_timer* pTimer)
-{
- if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
- wd_readw(pTimer->regs + WD_DCNTR);
- }
-}
-
-/* Stop a running watchdog timer-- the timer actually keeps
- * running, but the interrupt is masked so that no action is
- * taken upon expiration.
- *
- * pTimer - pointer to timer device
- */
-static void wd_stoptimer(struct wd_timer* pTimer)
-{
- if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
- wd_toggleintr(pTimer, WD_INTR_OFF);
-
- if(wd_dev.isbaddoggie) {
- pTimer->runstatus |= WD_STAT_BSTOP;
- wd_brokentimer((unsigned long)&wd_dev);
- }
- }
-}
-
-/* Start a watchdog timer with the specified limit value
- * If the watchdog is running, it will be restarted with
- * the provided limit value.
- *
- * This function will enable interrupts on the specified
- * watchdog.
- *
- * pTimer - pointer to timer device
- * limit - limit (countdown) value in 1/10th seconds
- */
-static void wd_starttimer(struct wd_timer* pTimer)
-{
- if(wd_dev.isbaddoggie) {
- pTimer->runstatus &= ~WD_STAT_BSTOP;
- }
- pTimer->runstatus &= ~WD_STAT_SVCD;
-
- wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT);
- wd_toggleintr(pTimer, WD_INTR_ON);
-}
-
-/* Restarts timer with maximum limit value and
- * does not unset 'brokenstop' value.
- */
-static void wd_resetbrokentimer(struct wd_timer* pTimer)
-{
- wd_toggleintr(pTimer, WD_INTR_ON);
- wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT);
-}
-
-/* Timer device initialization helper.
- * Returns 0 on success, other on failure
- */
-static int wd_inittimer(int whichdog)
-{
- struct miscdevice *whichmisc;
- void __iomem *whichregs;
- char whichident[8];
- int whichmask;
- __u16 whichlimit;
-
- switch(whichdog)
- {
- case WD0_ID:
- whichmisc = &wd0_miscdev;
- strcpy(whichident, "RIC");
- whichregs = wd_dev.regs + WD0_OFF;
- whichmask = WD0_INTR_MASK;
- whichlimit= (0 == wd0_timeout) ?
- (wd_dev.opt_timeout):
- (wd0_timeout);
- break;
- case WD1_ID:
- whichmisc = &wd1_miscdev;
- strcpy(whichident, "XIR");
- whichregs = wd_dev.regs + WD1_OFF;
- whichmask = WD1_INTR_MASK;
- whichlimit= (0 == wd1_timeout) ?
- (wd_dev.opt_timeout):
- (wd1_timeout);
- break;
- case WD2_ID:
- whichmisc = &wd2_miscdev;
- strcpy(whichident, "POR");
- whichregs = wd_dev.regs + WD2_OFF;
- whichmask = WD2_INTR_MASK;
- whichlimit= (0 == wd2_timeout) ?
- (wd_dev.opt_timeout):
- (wd2_timeout);
- break;
- default:
- printk("%s: %s: invalid watchdog id: %i\n",
- WD_OBPNAME, __func__, whichdog);
- return(1);
- }
- if(0 != misc_register(whichmisc))
- {
- return(1);
- }
- wd_dev.watchdog[whichdog].regs = whichregs;
- wd_dev.watchdog[whichdog].timeout = whichlimit;
- wd_dev.watchdog[whichdog].intr_mask = whichmask;
- wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP;
- wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT;
-
- printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n",
- WD_OBPNAME,
- whichdog,
- whichident,
- wd_dev.watchdog[whichdog].timeout / 10,
- wd_dev.watchdog[whichdog].timeout % 10,
- (0 != wd_dev.opt_enable) ? "in ENABLED mode" : "");
- return(0);
-}
-
-/* Timer method called to reset stopped watchdogs--
- * because of the PLD bug on CP1400, we cannot mask
- * interrupts within the PLD so me must continually
- * reset the timers ad infinitum.
- */
-static void wd_brokentimer(unsigned long data)
-{
- struct wd_device* pDev = (struct wd_device*)data;
- int id, tripped = 0;
-
- /* kill a running timer instance, in case we
- * were called directly instead of by kernel timer
- */
- if(timer_pending(&wd_timer)) {
- del_timer(&wd_timer);
- }
-
- for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
- if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) {
- ++tripped;
- wd_resetbrokentimer(&pDev->watchdog[id]);
- }
- }
-
- if(tripped) {
- /* there is at least one timer brokenstopped-- reschedule */
- init_timer(&wd_timer);
- wd_timer.expires = WD_BTIMEOUT;
- add_timer(&wd_timer);
- }
-}
-
-static int wd_getstatus(struct wd_timer* pTimer)
-{
- unsigned char stat = wd_readb(pTimer->regs + WD_STATUS);
- unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK);
- unsigned char ret = WD_STOPPED;
-
- /* determine STOPPED */
- if(0 == stat ) {
- return(ret);
- }
- /* determine EXPIRED vs FREERUN vs RUNNING */
- else if(WD_S_EXPIRED & stat) {
- ret = WD_EXPIRED;
- }
- else if(WD_S_RUNNING & stat) {
- if(intr & pTimer->intr_mask) {
- ret = WD_FREERUN;
- }
- else {
- /* Fudge WD_EXPIRED status for defective CP1400--
- * IF timer is running
- * AND brokenstop is set
- * AND an interrupt has been serviced
- * we are WD_EXPIRED.
- *
- * IF timer is running
- * AND brokenstop is set
- * AND no interrupt has been serviced
- * we are WD_FREERUN.
- */
- if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) {
- if(pTimer->runstatus & WD_STAT_SVCD) {
- ret = WD_EXPIRED;
- }
- else {
- /* we could as well pretend we are expired */
- ret = WD_FREERUN;
- }
- }
- else {
- ret = WD_RUNNING;
- }
- }
- }
-
- /* determine SERVICED */
- if(pTimer->runstatus & WD_STAT_SVCD) {
- ret |= WD_SERVICED;
- }
-
- return(ret);
-}
-
-static int __init wd_init(void)
-{
- int id;
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->ofdev.node->name, WD_OBPNAME))
- goto ebus_done;
- }
- }
-
-ebus_done:
- if(!edev) {
- printk("%s: unable to locate device\n", WD_OBPNAME);
- return -ENODEV;
- }
-
- wd_dev.regs =
- ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */
-
- if(NULL == wd_dev.regs) {
- printk("%s: unable to map registers\n", WD_OBPNAME);
- return(-ENODEV);
- }
-
- /* initialize device structure from OBP parameters */
- wd_dev.irq = edev->irqs[0];
- wd_dev.opt_enable = wd_opt_enable();
- wd_dev.opt_reboot = wd_opt_reboot();
- wd_dev.opt_timeout = wd_opt_timeout();
- wd_dev.isbaddoggie = wd_isbroken();
-
- /* disable all interrupts unless watchdog-enabled? == true */
- if(! wd_dev.opt_enable) {
- wd_toggleintr(NULL, WD_INTR_OFF);
- }
-
- /* register miscellaneous devices */
- for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
- if(0 != wd_inittimer(id)) {
- printk("%s%i: unable to initialize\n", WD_OBPNAME, id);
- }
- }
-
- /* warn about possible defective PLD */
- if(wd_dev.isbaddoggie) {
- init_timer(&wd_timer);
- wd_timer.function = wd_brokentimer;
- wd_timer.data = (unsigned long)&wd_dev;
- wd_timer.expires = WD_BTIMEOUT;
-
- printk("%s: PLD defect workaround enabled for model %s\n",
- WD_OBPNAME, WD_BADMODEL);
- }
- return(0);
-}
-
-static void __exit wd_cleanup(void)
-{
- int id;
-
- /* if 'watchdog-enable?' == TRUE, timers are not stopped
- * when module is unloaded. All brokenstopped timers will
- * also now eventually trip.
- */
- for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
- if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) {
- if(wd_dev.opt_enable) {
- printk(KERN_WARNING "%s%i: timer not stopped at release\n",
- WD_OBPNAME, id);
- }
- else {
- wd_stoptimer(&wd_dev.watchdog[id]);
- if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) {
- wd_resetbrokentimer(&wd_dev.watchdog[id]);
- printk(KERN_WARNING
- "%s%i: defect workaround disabled at release, "\
- "timer expires in ~%01i sec\n",
- WD_OBPNAME, id,
- wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10);
- }
- }
- }
- }
-
- if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) {
- del_timer(&wd_timer);
- }
- if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) {
- misc_deregister(&wd0_miscdev);
- }
- if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) {
- misc_deregister(&wd1_miscdev);
- }
- if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) {
- misc_deregister(&wd2_miscdev);
- }
- if(0 != wd_dev.initialized) {
- free_irq(wd_dev.irq, (void *)wd_dev.regs);
- }
- iounmap(wd_dev.regs);
-}
-
-module_init(wd_init);
-module_exit(wd_cleanup);
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index d8f5c0ca236..2550af4ae43 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -1,10 +1,7 @@
-/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $
- *
- * display7seg - Driver implementation for the 7-segment display
- * present on Sun Microsystems CP1400 and CP1500
+/* display7seg.c - Driver implementation for the 7-segment display
+ * present on Sun Microsystems CP1400 and CP1500
*
* Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- *
*/
#include <linux/kernel.h>
@@ -16,22 +13,20 @@
#include <linux/miscdevice.h>
#include <linux/ioport.h> /* request_region */
#include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/atomic.h>
-#include <asm/ebus.h> /* EBus device */
-#include <asm/oplib.h> /* OpenProm Library */
#include <asm/uaccess.h> /* put_/get_user */
#include <asm/io.h>
#include <asm/display7seg.h>
#define D7S_MINOR 193
-#define D7S_OBPNAME "display7seg"
-#define D7S_DEVNAME "d7s"
+#define DRIVER_NAME "d7s"
+#define PFX DRIVER_NAME ": "
static int sol_compat = 0; /* Solaris compatibility mode */
-#ifdef MODULE
-
/* Solaris compatibility flag -
* The Solaris implementation omits support for several
* documented driver features (ref Sun doc 806-0180-03).
@@ -46,20 +41,20 @@ static int sol_compat = 0; /* Solaris compatibility mode */
* If you wish the device to operate as under Solaris,
* omitting above features, set this parameter to non-zero.
*/
-module_param
- (sol_compat, int, 0);
-MODULE_PARM_DESC
- (sol_compat,
- "Disables documented functionality omitted from Solaris driver");
-
-MODULE_AUTHOR
- ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
- ("7-Segment Display driver for Sun Microsystems CP1400/1500");
+module_param(sol_compat, int, 0);
+MODULE_PARM_DESC(sol_compat,
+ "Disables documented functionality omitted from Solaris driver");
+
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500");
MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
- ("d7s");
-#endif /* ifdef MODULE */
+MODULE_SUPPORTED_DEVICE("d7s");
+
+struct d7s {
+ void __iomem *regs;
+ bool flipped;
+};
+struct d7s *d7s_device;
/*
* Register block address- see header for details
@@ -72,22 +67,6 @@ MODULE_SUPPORTED_DEVICE
* FLIP - Inverts display for upside-down mounted board
* bits 0-4 - 7-segment display contents
*/
-static void __iomem* d7s_regs;
-
-static inline void d7s_free(void)
-{
- iounmap(d7s_regs);
-}
-
-static inline int d7s_obpflipped(void)
-{
- int opt_node;
-
- opt_node = prom_getchild(prom_root_node);
- opt_node = prom_searchsiblings(opt_node, "options");
- return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1);
-}
-
static atomic_t d7s_users = ATOMIC_INIT(0);
static int d7s_open(struct inode *inode, struct file *f)
@@ -106,12 +85,15 @@ static int d7s_release(struct inode *inode, struct file *f)
* are not operating in solaris-compat mode
*/
if (atomic_dec_and_test(&d7s_users) && !sol_compat) {
- int regval = 0;
-
- regval = readb(d7s_regs);
- (0 == d7s_obpflipped()) ?
- writeb(regval |= D7S_FLIP, d7s_regs):
- writeb(regval &= ~D7S_FLIP, d7s_regs);
+ struct d7s *p = d7s_device;
+ u8 regval = 0;
+
+ regval = readb(p->regs);
+ if (p->flipped)
+ regval |= D7S_FLIP;
+ else
+ regval &= ~D7S_FLIP;
+ writeb(regval, p->regs);
}
return 0;
@@ -119,9 +101,10 @@ static int d7s_release(struct inode *inode, struct file *f)
static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- __u8 regs = readb(d7s_regs);
- __u8 ireg = 0;
+ struct d7s *p = d7s_device;
+ u8 regs = readb(p->regs);
int error = 0;
+ u8 ireg = 0;
if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
return -ENODEV;
@@ -129,18 +112,20 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
lock_kernel();
switch (cmd) {
case D7SIOCWR:
- /* assign device register values
- * we mask-out D7S_FLIP if in sol_compat mode
+ /* assign device register values we mask-out D7S_FLIP
+ * if in sol_compat mode
*/
if (get_user(ireg, (int __user *) arg)) {
error = -EFAULT;
break;
}
- if (0 != sol_compat) {
- (regs & D7S_FLIP) ?
- (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP);
+ if (sol_compat) {
+ if (regs & D7S_FLIP)
+ ireg |= D7S_FLIP;
+ else
+ ireg &= ~D7S_FLIP;
}
- writeb(ireg, d7s_regs);
+ writeb(ireg, p->regs);
break;
case D7SIOCRD:
@@ -158,9 +143,11 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case D7SIOCTM:
/* toggle device mode-- flip display orientation */
- (regs & D7S_FLIP) ?
- (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP);
- writeb(regs, d7s_regs);
+ if (regs & D7S_FLIP)
+ regs &= ~D7S_FLIP;
+ else
+ regs |= D7S_FLIP;
+ writeb(regs, p->regs);
break;
};
unlock_kernel();
@@ -176,69 +163,123 @@ static const struct file_operations d7s_fops = {
.release = d7s_release,
};
-static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
+static struct miscdevice d7s_miscdev = {
+ .minor = D7S_MINOR,
+ .name = DRIVER_NAME,
+ .fops = &d7s_fops
+};
-static int __init d7s_init(void)
+static int __devinit d7s_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
- int iTmp = 0, regs = 0;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
- goto ebus_done;
- }
+ struct device_node *opts;
+ int err = -EINVAL;
+ struct d7s *p;
+ u8 regs;
+
+ if (d7s_device)
+ goto out;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!p)
+ goto out;
+
+ p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s");
+ if (!p->regs) {
+ printk(KERN_ERR PFX "Cannot map chip registers\n");
+ goto out_free;
}
-ebus_done:
- if(!edev) {
- printk("%s: unable to locate device\n", D7S_DEVNAME);
- return -ENODEV;
+ err = misc_register(&d7s_miscdev);
+ if (err) {
+ printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n",
+ D7S_MINOR);
+ goto out_iounmap;
}
- d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8));
-
- iTmp = misc_register(&d7s_miscdev);
- if (0 != iTmp) {
- printk("%s: unable to acquire miscdevice minor %i\n",
- D7S_DEVNAME, D7S_MINOR);
- iounmap(d7s_regs);
- return iTmp;
- }
-
- /* OBP option "d7s-flipped?" is honored as default
- * for the device, and reset default when detached
+ /* OBP option "d7s-flipped?" is honored as default for the
+ * device, and reset default when detached
*/
- regs = readb(d7s_regs);
- iTmp = d7s_obpflipped();
- (0 == iTmp) ?
- writeb(regs |= D7S_FLIP, d7s_regs):
- writeb(regs &= ~D7S_FLIP, d7s_regs);
-
- printk("%s: 7-Segment Display%s at 0x%lx %s\n",
- D7S_DEVNAME,
- (0 == iTmp) ? (" (FLIPPED)") : (""),
- edev->resource[0].start,
- (0 != sol_compat) ? ("in sol_compat mode") : (""));
-
- return 0;
+ regs = readb(p->regs);
+ opts = of_find_node_by_path("/options");
+ if (opts &&
+ of_get_property(opts, "d7s-flipped?", NULL))
+ p->flipped = true;
+
+ if (p->flipped)
+ regs |= D7S_FLIP;
+ else
+ regs &= ~D7S_FLIP;
+
+ writeb(regs, p->regs);
+
+ printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n",
+ op->node->full_name,
+ (regs & D7S_FLIP) ? " (FLIPPED)" : "",
+ op->resource[0].start,
+ sol_compat ? "in sol_compat mode" : "");
+
+ dev_set_drvdata(&op->dev, p);
+ d7s_device = p;
+ err = 0;
+
+out:
+ return err;
+
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+
+out_free:
+ kfree(p);
+ goto out;
}
-static void __exit d7s_cleanup(void)
+static int __devexit d7s_remove(struct of_device *op)
{
- int regs = readb(d7s_regs);
+ struct d7s *p = dev_get_drvdata(&op->dev);
+ u8 regs = readb(p->regs);
/* Honor OBP d7s-flipped? unless operating in solaris-compat mode */
- if (0 == sol_compat) {
- (0 == d7s_obpflipped()) ?
- writeb(regs |= D7S_FLIP, d7s_regs):
- writeb(regs &= ~D7S_FLIP, d7s_regs);
+ if (sol_compat) {
+ if (p->flipped)
+ regs |= D7S_FLIP;
+ else
+ regs &= ~D7S_FLIP;
+ writeb(regs, p->regs);
}
misc_deregister(&d7s_miscdev);
- d7s_free();
+ of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+ kfree(p);
+
+ return 0;
+}
+
+static const struct of_device_id d7s_match[] = {
+ {
+ .name = "display7seg",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, d7s_match);
+
+static struct of_platform_driver d7s_driver = {
+ .name = DRIVER_NAME,
+ .match_table = d7s_match,
+ .probe = d7s_probe,
+ .remove = __devexit_p(d7s_remove),
+};
+
+static int __init d7s_init(void)
+{
+ return of_register_driver(&d7s_driver, &of_bus_type);
+}
+
+static void __exit d7s_exit(void)
+{
+ of_unregister_driver(&d7s_driver);
}
module_init(d7s_init);
-module_exit(d7s_cleanup);
+module_exit(d7s_exit);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index a408402426f..58e583b61e6 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1,5 +1,4 @@
-/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $
- * envctrl.c: Temperature and Fan monitoring on Machines providing it.
+/* envctrl.c: Temperature and Fan monitoring on Machines providing it.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com)
@@ -28,12 +27,16 @@
#include <linux/kmod.h>
#include <linux/reboot.h>
#include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
-#include <asm/ebus.h>
#include <asm/uaccess.h>
#include <asm/envctrl.h>
#include <asm/io.h>
+#define DRIVER_NAME "envctrl"
+#define PFX DRIVER_NAME ": "
+
#define ENVCTRL_MINOR 162
#define PCF8584_ADDRESS 0x55
@@ -193,7 +196,7 @@ static void envtrl_i2c_test_pin(void)
}
if (limit <= 0)
- printk(KERN_INFO "envctrl: Pin status will not clear.\n");
+ printk(KERN_INFO PFX "Pin status will not clear.\n");
}
/* Function Description: Test busy bit.
@@ -211,7 +214,7 @@ static void envctrl_i2c_test_bb(void)
}
if (limit <= 0)
- printk(KERN_INFO "envctrl: Busy bit will not clear.\n");
+ printk(KERN_INFO PFX "Busy bit will not clear.\n");
}
/* Function Description: Send the address for a read access.
@@ -858,11 +861,10 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
/* Function Description: Initialize i2c child device.
* Return: None.
*/
-static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
+static void envctrl_init_i2c_child(struct device_node *dp,
struct i2c_child_t *pchild)
{
int len, i, tbls_size = 0;
- struct device_node *dp = edev_child->prom_node;
const void *pval;
/* Get device address. */
@@ -882,12 +884,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
pchild->tables = kmalloc(tbls_size, GFP_KERNEL);
if (pchild->tables == NULL){
- printk("envctrl: Failed to allocate table.\n");
+ printk(KERN_ERR PFX "Failed to allocate table.\n");
return;
}
pval = of_get_property(dp, "tables", &len);
if (!pval || len <= 0) {
- printk("envctrl: Failed to get table.\n");
+ printk(KERN_ERR PFX "Failed to get table.\n");
return;
}
memcpy(pchild->tables, pval, len);
@@ -993,14 +995,14 @@ static int kenvctrld(void *__unused)
struct i2c_child_t *cputemp;
if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) {
- printk(KERN_ERR
- "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n");
+ printk(KERN_ERR PFX
+ "kenvctrld unable to monitor CPU temp-- exiting\n");
return -ENODEV;
}
poll_interval = 5000; /* TODO env_mon_interval */
- printk(KERN_INFO "envctrl: %s starting...\n", current->comm);
+ printk(KERN_INFO PFX "%s starting...\n", current->comm);
for (;;) {
msleep_interruptible(poll_interval);
@@ -1022,54 +1024,35 @@ static int kenvctrld(void *__unused)
}
}
}
- printk(KERN_INFO "envctrl: %s exiting...\n", current->comm);
+ printk(KERN_INFO PFX "%s exiting...\n", current->comm);
return 0;
}
-static int __init envctrl_init(void)
+static int __devinit envctrl_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
- struct linux_ebus_child *edev_child = NULL;
- int err, i = 0;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "bbc")) {
- /* If we find a boot-bus controller node,
- * then this envctrl driver is not for us.
- */
- return -ENODEV;
- }
- }
- }
+ struct device_node *dp;
+ int index, err;
- /* Traverse through ebus and ebus device list for i2c device and
- * adc and gpio nodes.
- */
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "i2c")) {
- i2c = ioremap(edev->resource[0].start, 0x2);
- for_each_edevchild(edev, edev_child) {
- if (!strcmp("gpio", edev_child->prom_node->name)) {
- i2c_childlist[i].i2ctype = I2C_GPIO;
- envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
- }
- if (!strcmp("adc", edev_child->prom_node->name)) {
- i2c_childlist[i].i2ctype = I2C_ADC;
- envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
- }
- }
- goto done;
- }
+ if (i2c)
+ return -EINVAL;
+
+ i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME);
+ if (!i2c)
+ return -ENOMEM;
+
+ index = 0;
+ dp = op->node->child;
+ while (dp) {
+ if (!strcmp(dp->name, "gpio")) {
+ i2c_childlist[index].i2ctype = I2C_GPIO;
+ envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
+ } else if (!strcmp(dp->name, "adc")) {
+ i2c_childlist[index].i2ctype = I2C_ADC;
+ envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
}
- }
-done:
- if (!edev) {
- printk("envctrl: I2C device not found.\n");
- return -ENODEV;
+ dp = dp->sibling;
}
/* Set device address. */
@@ -1087,7 +1070,7 @@ done:
/* Register the device as a minor miscellaneous device. */
err = misc_register(&envctrl_dev);
if (err) {
- printk("envctrl: Unable to get misc minor %d\n",
+ printk(KERN_ERR PFX "Unable to get misc minor %d\n",
envctrl_dev.minor);
goto out_iounmap;
}
@@ -1096,12 +1079,12 @@ done:
* a next child device, so we decrement before reverse-traversal of
* child devices.
*/
- printk("envctrl: initialized ");
- for (--i; i >= 0; --i) {
+ printk(KERN_INFO PFX "Initialized ");
+ for (--index; index >= 0; --index) {
printk("[%s 0x%lx]%s",
- (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") :
- ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")),
- i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
+ (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" :
+ ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"),
+ i2c_childlist[index].addr, (0 == index) ? "\n" : " ");
}
kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -1115,26 +1098,54 @@ done:
out_deregister:
misc_deregister(&envctrl_dev);
out_iounmap:
- iounmap(i2c);
- for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
- kfree(i2c_childlist[i].tables);
+ of_iounmap(&op->resource[0], i2c, 0x2);
+ for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+ kfree(i2c_childlist[index].tables);
return err;
}
-static void __exit envctrl_cleanup(void)
+static int __devexit envctrl_remove(struct of_device *op)
{
- int i;
+ int index;
kthread_stop(kenvctrld_task);
- iounmap(i2c);
+ of_iounmap(&op->resource[0], i2c, 0x2);
misc_deregister(&envctrl_dev);
- for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
- kfree(i2c_childlist[i].tables);
+ for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+ kfree(i2c_childlist[index].tables);
+
+ return 0;
+}
+
+static const struct of_device_id envctrl_match[] = {
+ {
+ .name = "i2c",
+ .compatible = "i2cpcf,8584",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, envctrl_match);
+
+static struct of_platform_driver envctrl_driver = {
+ .name = DRIVER_NAME,
+ .match_table = envctrl_match,
+ .probe = envctrl_probe,
+ .remove = __devexit_p(envctrl_remove),
+};
+
+static int __init envctrl_init(void)
+{
+ return of_register_driver(&envctrl_driver, &of_bus_type);
+}
+
+static void __exit envctrl_exit(void)
+{
+ of_unregister_driver(&envctrl_driver);
}
module_init(envctrl_init);
-module_exit(envctrl_cleanup);
+module_exit(envctrl_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 7d95e151513..41083472ff4 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -1,5 +1,4 @@
-/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $
- * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
+/* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
@@ -15,13 +14,13 @@
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/ebus.h>
#include <asm/upa.h>
static DEFINE_SPINLOCK(flash_lock);
@@ -161,97 +160,68 @@ static const struct file_operations flash_fops = {
static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
-static int __init flash_init(void)
+static int __devinit flash_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
-#ifdef CONFIG_PCI
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev = NULL;
- struct linux_prom_registers regs[2];
- int len, nregs;
-#endif
- int err;
-
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "flashprom")) {
- if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) {
- flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
- (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
- flash.read_size = sdev->reg_addrs[0].reg_size;
- flash.write_base = flash.read_base;
- flash.write_size = flash.read_size;
- } else {
- flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
- (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
- flash.read_size = sdev->reg_addrs[0].reg_size;
- flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) |
- (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL);
- flash.write_size = sdev->reg_addrs[1].reg_size;
- }
- flash.busy = 0;
- break;
- }
- }
- if (!sdev) {
-#ifdef CONFIG_PCI
- const struct linux_prom_registers *ebus_regs;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_node->name, "flashprom"))
- goto ebus_done;
- }
- }
- ebus_done:
- if (!edev)
- return -ENODEV;
-
- ebus_regs = of_get_property(edev->prom_node, "reg", &len);
- if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
- printk("flash: Strange reg property size %d\n", len);
- return -ENODEV;
- }
-
- nregs = len / sizeof(ebus_regs[0]);
+ struct device_node *dp = op->node;
+ struct device_node *parent;
- flash.read_base = edev->resource[0].start;
- flash.read_size = ebus_regs[0].reg_size;
+ parent = dp->parent;
- if (nregs == 1) {
- flash.write_base = edev->resource[0].start;
- flash.write_size = ebus_regs[0].reg_size;
- } else if (nregs == 2) {
- flash.write_base = edev->resource[1].start;
- flash.write_size = ebus_regs[1].reg_size;
- } else {
- printk("flash: Strange number of regs %d\n", nregs);
- return -ENODEV;
- }
-
- flash.busy = 0;
-
-#else
+ if (strcmp(parent->name, "sbus") &&
+ strcmp(parent->name, "sbi") &&
+ strcmp(parent->name, "ebus"))
return -ENODEV;
-#endif
+
+ flash.read_base = op->resource[0].start;
+ flash.read_size = resource_size(&op->resource[0]);
+ if (op->resource[1].flags) {
+ flash.write_base = op->resource[1].start;
+ flash.write_size = resource_size(&op->resource[1]);
+ } else {
+ flash.write_base = op->resource[0].start;
+ flash.write_size = resource_size(&op->resource[0]);
}
+ flash.busy = 0;
- printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
+ printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
+ op->node->full_name,
flash.read_base, flash.read_size,
flash.write_base, flash.write_size);
- err = misc_register(&flash_dev);
- if (err) {
- printk(KERN_ERR "flash: unable to get misc minor\n");
- return err;
- }
+ return misc_register(&flash_dev);
+}
+
+static int __devexit flash_remove(struct of_device *op)
+{
+ misc_deregister(&flash_dev);
return 0;
}
+static const struct of_device_id flash_match[] = {
+ {
+ .name = "flashprom",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, flash_match);
+
+static struct of_platform_driver flash_driver = {
+ .name = "flash",
+ .match_table = flash_match,
+ .probe = flash_probe,
+ .remove = __devexit_p(flash_remove),
+};
+
+static int __init flash_init(void)
+{
+ return of_register_driver(&flash_driver, &of_bus_type);
+}
+
static void __exit flash_cleanup(void)
{
- misc_deregister(&flash_dev);
+ of_unregister_driver(&flash_driver);
}
module_init(flash_init);
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
deleted file mode 100644
index b0429917154..00000000000
--- a/drivers/sbus/char/rtc.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $
- *
- * Linux/SPARC Real Time Clock Driver
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- *
- * This is a little driver that lets a user-level program access
- * the SPARC Mostek real time clock chip. It is no use unless you
- * use the modified clock utility.
- *
- * Get the modified clock utility from:
- * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c
- */
-
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/rtc.h>
-
-static int rtc_busy = 0;
-
-/* This is the structure layout used by drivers/char/rtc.c, we
- * support that driver's ioctls so that things are less messy in
- * userspace.
- */
-struct rtc_time_generic {
- int tm_sec;
- int tm_min;
- int tm_hour;
- int tm_mday;
- int tm_mon;
- int tm_year;
- int tm_wday;
- int tm_yday;
- int tm_isdst;
-};
-#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */
-#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */
-#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
-#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */
-#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */
-#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */
-#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */
-#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */
-#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time */
-#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time */
-#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */
-#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */
-#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */
-#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */
-#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
-#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
-#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
-#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
-#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */
-#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */
-
-/* Retrieve the current date and time from the real time clock. */
-static void get_rtc_time(struct rtc_time *t)
-{
- void __iomem *regs = mstk48t02_regs;
- u8 tmp;
-
- spin_lock_irq(&mostek_lock);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- t->sec = MSTK_REG_SEC(regs);
- t->min = MSTK_REG_MIN(regs);
- t->hour = MSTK_REG_HOUR(regs);
- t->dow = MSTK_REG_DOW(regs);
- t->dom = MSTK_REG_DOM(regs);
- t->month = MSTK_REG_MONTH(regs);
- t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
-}
-
-/* Set the current date and time inthe real time clock. */
-void set_rtc_time(struct rtc_time *t)
-{
- void __iomem *regs = mstk48t02_regs;
- u8 tmp;
-
- spin_lock_irq(&mostek_lock);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- MSTK_SET_REG_SEC(regs,t->sec);
- MSTK_SET_REG_MIN(regs,t->min);
- MSTK_SET_REG_HOUR(regs,t->hour);
- MSTK_SET_REG_DOW(regs,t->dow);
- MSTK_SET_REG_DOM(regs,t->dom);
- MSTK_SET_REG_MONTH(regs,t->month);
- MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO);
-
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- spin_unlock_irq(&mostek_lock);
-}
-
-static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm)
-{
- struct rtc_time_generic __user *utm = argp;
-
- if (__put_user(tm->sec, &utm->tm_sec) ||
- __put_user(tm->min, &utm->tm_min) ||
- __put_user(tm->hour, &utm->tm_hour) ||
- __put_user(tm->dom, &utm->tm_mday) ||
- __put_user(tm->month, &utm->tm_mon) ||
- __put_user(tm->year, &utm->tm_year) ||
- __put_user(tm->dow, &utm->tm_wday) ||
- __put_user(0, &utm->tm_yday) ||
- __put_user(0, &utm->tm_isdst))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp)
-{
- struct rtc_time_generic __user *utm = argp;
-
- if (__get_user(tm->sec, &utm->tm_sec) ||
- __get_user(tm->min, &utm->tm_min) ||
- __get_user(tm->hour, &utm->tm_hour) ||
- __get_user(tm->dom, &utm->tm_mday) ||
- __get_user(tm->month, &utm->tm_mon) ||
- __get_user(tm->year, &utm->tm_year) ||
- __get_user(tm->dow, &utm->tm_wday))
- return -EFAULT;
-
- return 0;
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct rtc_time rtc_tm;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- /* No interrupt support, return an error
- * compatible with drivers/char/rtc.c
- */
- case RTC_AIE_OFF:
- case RTC_AIE_ON:
- case RTC_PIE_OFF:
- case RTC_PIE_ON:
- case RTC_UIE_OFF:
- case RTC_UIE_ON:
- case RTC_IRQP_READ:
- case RTC_IRQP_SET:
- case RTC_EPOCH_SET:
- case RTC_EPOCH_READ:
- return -EINVAL;
-
- case RTCGET:
- case RTC_RD_TIME:
- memset(&rtc_tm, 0, sizeof(struct rtc_time));
- get_rtc_time(&rtc_tm);
-
- if (cmd == RTCGET) {
- if (copy_to_user(argp, &rtc_tm,
- sizeof(struct rtc_time)))
- return -EFAULT;
- } else if (put_rtc_time_generic(argp, &rtc_tm))
- return -EFAULT;
-
- return 0;
-
-
- case RTCSET:
- case RTC_SET_TIME:
- if (!capable(CAP_SYS_TIME))
- return -EPERM;
-
- if (cmd == RTCSET) {
- if (copy_from_user(&rtc_tm, argp,
- sizeof(struct rtc_time)))
- return -EFAULT;
- } else if (get_rtc_time_generic(&rtc_tm, argp))
- return -EFAULT;
-
- set_rtc_time(&rtc_tm);
-
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
- int ret;
-
- lock_kernel();
- spin_lock_irq(&mostek_lock);
- if (rtc_busy) {
- ret = -EBUSY;
- } else {
- rtc_busy = 1;
- ret = 0;
- }
- spin_unlock_irq(&mostek_lock);
- unlock_kernel();
-
- return ret;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
- rtc_busy = 0;
-
- return 0;
-}
-
-static const struct file_operations rtc_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = rtc_ioctl,
- .open = rtc_open,
- .release = rtc_release,
-};
-
-static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
-
-static int __init rtc_sun_init(void)
-{
- int error;
-
- /* It is possible we are being driven by some other RTC chip
- * and thus another RTC driver is handling things.
- */
- if (!mstk48t02_regs)
- return -ENODEV;
-
- error = misc_register(&rtc_dev);
- if (error) {
- printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n");
- return error;
- }
- printk("rtc_sun_init: Registered Mostek RTC driver.\n");
-
- return 0;
-}
-
-static void __exit rtc_sun_cleanup(void)
-{
- misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_sun_init);
-module_exit(rtc_sun_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 777637594ac..27993c37775 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -1,7 +1,7 @@
-/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $
- * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
+/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
*
* Copyright 1999 Derrick J Brashear (shadow@dementia.org)
+ * Copyright 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -14,6 +14,8 @@
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
@@ -21,7 +23,6 @@
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/sbus.h>
#define UCTRL_MINOR 174
@@ -33,26 +34,26 @@
#endif
struct uctrl_regs {
- volatile u32 uctrl_intr;
- volatile u32 uctrl_data;
- volatile u32 uctrl_stat;
- volatile u32 uctrl_xxx[5];
+ u32 uctrl_intr;
+ u32 uctrl_data;
+ u32 uctrl_stat;
+ u32 uctrl_xxx[5];
};
struct ts102_regs {
- volatile u32 card_a_intr;
- volatile u32 card_a_stat;
- volatile u32 card_a_ctrl;
- volatile u32 card_a_xxx;
- volatile u32 card_b_intr;
- volatile u32 card_b_stat;
- volatile u32 card_b_ctrl;
- volatile u32 card_b_xxx;
- volatile u32 uctrl_intr;
- volatile u32 uctrl_data;
- volatile u32 uctrl_stat;
- volatile u32 uctrl_xxx;
- volatile u32 ts102_xxx[4];
+ u32 card_a_intr;
+ u32 card_a_stat;
+ u32 card_a_ctrl;
+ u32 card_a_xxx;
+ u32 card_b_intr;
+ u32 card_b_stat;
+ u32 card_b_ctrl;
+ u32 card_b_xxx;
+ u32 uctrl_intr;
+ u32 uctrl_data;
+ u32 uctrl_stat;
+ u32 uctrl_xxx;
+ u32 ts102_xxx[4];
};
/* Bits for uctrl_intr register */
@@ -186,17 +187,15 @@ enum uctrl_opcode {
POWER_RESTART=0x83,
};
-struct uctrl_driver {
- struct uctrl_regs *regs;
+static struct uctrl_driver {
+ struct uctrl_regs __iomem *regs;
int irq;
int pending;
struct uctrl_status status;
-};
-
-static struct uctrl_driver drv;
+} *global_driver;
-static void uctrl_get_event_status(void);
-static void uctrl_get_external_status(void);
+static void uctrl_get_event_status(struct uctrl_driver *);
+static void uctrl_get_external_status(struct uctrl_driver *);
static int
uctrl_ioctl(struct inode *inode, struct file *file,
@@ -213,16 +212,14 @@ static int
uctrl_open(struct inode *inode, struct file *file)
{
lock_kernel();
- uctrl_get_event_status();
- uctrl_get_external_status();
+ uctrl_get_event_status(global_driver);
+ uctrl_get_external_status(global_driver);
unlock_kernel();
return 0;
}
static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
{
- struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
- printk("in uctrl_interrupt\n");
return IRQ_HANDLED;
}
@@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = {
{ \
unsigned int i; \
for (i = 0; i < 10000; i++) { \
- if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \
+ if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \
break; \
} \
dprintk(("write data 0x%02x\n", value)); \
- driver->regs->uctrl_data = value; \
+ sbus_writel(value, &driver->regs->uctrl_data); \
}
/* Wait for something to read, read it, then clear the bit */
@@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = {
unsigned int i; \
value = 0; \
for (i = 0; i < 10000; i++) { \
- if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \
+ if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \
break; \
udelay(1); \
} \
- value = driver->regs->uctrl_data; \
+ value = sbus_readl(&driver->regs->uctrl_data); \
dprintk(("read data 0x%02x\n", value)); \
- driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \
+ sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \
}
-static void uctrl_do_txn(struct uctrl_txn *txn)
+static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn)
{
- struct uctrl_driver *driver = &drv;
int stat, incnt, outcnt, bytecnt, intr;
u32 byte;
- stat = driver->regs->uctrl_stat;
- intr = driver->regs->uctrl_intr;
- driver->regs->uctrl_stat = stat;
+ stat = sbus_readl(&driver->regs->uctrl_stat);
+ intr = sbus_readl(&driver->regs->uctrl_intr);
+ sbus_writel(stat, &driver->regs->uctrl_stat);
dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr));
@@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn)
}
}
-static void uctrl_get_event_status(void)
+static void uctrl_get_event_status(struct uctrl_driver *driver)
{
- struct uctrl_driver *driver = &drv;
struct uctrl_txn txn;
u8 outbits[2];
@@ -317,7 +312,7 @@ static void uctrl_get_event_status(void)
txn.inbuf = NULL;
txn.outbuf = outbits;
- uctrl_do_txn(&txn);
+ uctrl_do_txn(driver, &txn);
dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
driver->status.event_status =
@@ -325,9 +320,8 @@ static void uctrl_get_event_status(void)
dprintk(("ev is %x\n", driver->status.event_status));
}
-static void uctrl_get_external_status(void)
+static void uctrl_get_external_status(struct uctrl_driver *driver)
{
- struct uctrl_driver *driver = &drv;
struct uctrl_txn txn;
u8 outbits[2];
int i, v;
@@ -338,7 +332,7 @@ static void uctrl_get_external_status(void)
txn.inbuf = NULL;
txn.outbuf = outbits;
- uctrl_do_txn(&txn);
+ uctrl_do_txn(driver, &txn);
dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
driver->status.external_status =
@@ -354,71 +348,101 @@ static void uctrl_get_external_status(void)
}
-static int __init ts102_uctrl_init(void)
+static int __devinit uctrl_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct uctrl_driver *driver = &drv;
- int len;
- struct linux_prom_irqs tmp_irq[2];
- unsigned int vaddr[2] = { 0, 0 };
- int tmpnode, uctrlnode = prom_getchild(prom_root_node);
- int err;
+ struct uctrl_driver *p;
+ int err = -ENOMEM;
- tmpnode = prom_searchsiblings(uctrlnode, "obio");
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR "uctrl: Unable to allocate device struct.\n");
+ goto out;
+ }
- if (tmpnode)
- uctrlnode = prom_getchild(tmpnode);
+ p->regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "uctrl");
+ if (!p->regs) {
+ printk(KERN_ERR "uctrl: Unable to map registers.\n");
+ goto out_free;
+ }
- uctrlnode = prom_searchsiblings(uctrlnode, "uctrl");
+ p->irq = op->irqs[0];
+ err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
+ if (err) {
+ printk(KERN_ERR "uctrl: Unable to register irq.\n");
+ goto out_iounmap;
+ }
- if (!uctrlnode)
- return -ENODEV;
+ err = misc_register(&uctrl_dev);
+ if (err) {
+ printk(KERN_ERR "uctrl: Unable to register misc device.\n");
+ goto out_free_irq;
+ }
- /* the prom mapped it for us */
- len = prom_getproperty(uctrlnode, "address", (void *) vaddr,
- sizeof(vaddr));
- driver->regs = (struct uctrl_regs *)vaddr[0];
+ sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr);
+ printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n",
+ op->node->full_name, p->regs, p->irq);
+ uctrl_get_event_status(p);
+ uctrl_get_external_status(p);
- len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq,
- sizeof(tmp_irq));
+ dev_set_drvdata(&op->dev, p);
+ global_driver = p;
- /* Flush device */
- READUCTLDATA(len);
+out:
+ return err;
- if(!driver->irq)
- driver->irq = tmp_irq[0].pri;
+out_free_irq:
+ free_irq(p->irq, p);
- err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
- if (err) {
- printk("%s: unable to register irq %d\n",
- __func__, driver->irq);
- return err;
- }
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
- if (misc_register(&uctrl_dev)) {
- printk("%s: unable to get misc minor %d\n",
- __func__, uctrl_dev.minor);
- free_irq(driver->irq, driver);
- return -ENODEV;
- }
+out_free:
+ kfree(p);
+ goto out;
+}
- driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK;
- printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq);
- uctrl_get_event_status();
- uctrl_get_external_status();
- return 0;
+static int __devexit uctrl_remove(struct of_device *op)
+{
+ struct uctrl_driver *p = dev_get_drvdata(&op->dev);
+
+ if (p) {
+ misc_deregister(&uctrl_dev);
+ free_irq(p->irq, p);
+ of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
+ kfree(p);
+ }
+ return 0;
}
-static void __exit ts102_uctrl_cleanup(void)
+static const struct of_device_id uctrl_match[] = {
+ {
+ .name = "uctrl",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, uctrl_match);
+
+static struct of_platform_driver uctrl_driver = {
+ .name = "uctrl",
+ .match_table = uctrl_match,
+ .probe = uctrl_probe,
+ .remove = __devexit_p(uctrl_remove),
+};
+
+
+static int __init uctrl_init(void)
{
- struct uctrl_driver *driver = &drv;
+ return of_register_driver(&uctrl_driver, &of_bus_type);
+}
- misc_deregister(&uctrl_dev);
- if (driver->irq)
- free_irq(driver->irq, driver);
- if (driver->regs)
- driver->regs = NULL;
+static void __exit uctrl_exit(void)
+{
+ of_unregister_driver(&uctrl_driver);
}
-module_init(ts102_uctrl_init);
-module_exit(ts102_uctrl_cleanup);
+module_init(uctrl_init);
+module_exit(uctrl_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
deleted file mode 100644
index a5240c52aa0..00000000000
--- a/drivers/sbus/char/vfc.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef _LINUX_VFC_H_
-#define _LINUX_VFC_H_
-
-/*
- * The control register for the vfc is at offset 0x4000
- * The first field ram bank is located at offset 0x5000
- * The second field ram bank is at offset 0x7000
- * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c)
- * data and transmit register.
- * i2c_s1 controls register s1 of the PCF8584
- * i2c_write seems to be similar to i2c_write but I am not
- * quite sure why sun uses it
- *
- * I am also not sure whether or not you can read the fram bank as a
- * whole or whether you must read each word individually from offset
- * 0x5000 as soon as I figure it out I will update this file */
-
-struct vfc_regs {
- char pad1[0x4000];
- unsigned int control; /* Offset 0x4000 */
- char pad2[0xffb]; /* from offset 0x4004 to 0x5000 */
- unsigned int fram_bank1; /* Offset 0x5000 */
- char pad3[0xffb]; /* from offset 0x5004 to 0x6000 */
- unsigned int i2c_reg; /* Offset 0x6000 */
- unsigned int i2c_magic2; /* Offset 0x6004 */
- unsigned int i2c_s1; /* Offset 0x6008 */
- unsigned int i2c_write; /* Offset 0x600c */
- char pad4[0xff0]; /* from offset 0x6010 to 0x7000 */
- unsigned int fram_bank2; /* Offset 0x7000 */
- char pad5[0x1000];
-};
-
-#define VFC_SAA9051_NR (13)
-#define VFC_SAA9051_ADDR (0x8a)
- /* The saa9051 returns the following for its status
- * bit 0 - 0
- * bit 1 - SECAM color detected (1=found,0=not found)
- * bit 2 - COLOR detected (1=found,0=not found)
- * bit 3 - 0
- * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL))
- * bit 5 - 1
- * bit 6 - horizontal frequency lock (1=transmitter found,
- * 0=no transmitter)
- * bit 7 - Power on reset bit (1=reset,0=at least one successful
- * read of the status byte)
- */
-
-#define VFC_SAA9051_PONRES (0x80)
-#define VFC_SAA9051_HLOCK (0x40)
-#define VFC_SAA9051_FD (0x10)
-#define VFC_SAA9051_CD (0x04)
-#define VFC_SAA9051_CS (0x02)
-
-
-/* The various saa9051 sub addresses */
-
-#define VFC_SAA9051_IDEL (0)
-#define VFC_SAA9051_HSY_START (1)
-#define VFC_SAA9051_HSY_STOP (2)
-#define VFC_SAA9051_HC_START (3)
-#define VFC_SAA9051_HC_STOP (4)
-#define VFC_SAA9051_HS_START (5)
-#define VFC_SAA9051_HORIZ_PEAK (6)
-#define VFC_SAA9051_HUE (7)
-#define VFC_SAA9051_C1 (8)
-#define VFC_SAA9051_C2 (9)
-#define VFC_SAA9051_C3 (0xa)
-#define VFC_SAA9051_SECAM_DELAY (0xb)
-
-
-/* Bit settings for saa9051 sub address 0x06 */
-
-#define VFC_SAA9051_AP1 (0x01)
-#define VFC_SAA9051_AP2 (0x02)
-#define VFC_SAA9051_COR1 (0x04)
-#define VFC_SAA9051_COR2 (0x08)
-#define VFC_SAA9051_BP1 (0x10)
-#define VFC_SAA9051_BP2 (0x20)
-#define VFC_SAA9051_PF (0x40)
-#define VFC_SAA9051_BY (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x08 */
-
-#define VFC_SAA9051_CCFR0 (0x01)
-#define VFC_SAA9051_CCFR1 (0x02)
-#define VFC_SAA9051_YPN (0x04)
-#define VFC_SAA9051_ALT (0x08)
-#define VFC_SAA9051_CO (0x10)
-#define VFC_SAA9051_VTR (0x20)
-#define VFC_SAA9051_FS (0x40)
-#define VFC_SAA9051_HPLL (0x80)
-
-
-/* Bit settings for saa9051 sub address 9 */
-
-#define VFC_SAA9051_SS0 (0x01)
-#define VFC_SAA9051_SS1 (0x02)
-#define VFC_SAA9051_AFCC (0x04)
-#define VFC_SAA9051_CI (0x08)
-#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */
-#define VFC_SAA9051_OEC (0x20)
-#define VFC_SAA9051_OEY (0x40)
-#define VFC_SAA9051_VNL (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x0A */
-
-#define VFC_SAA9051_YDL0 (0x01)
-#define VFC_SAA9051_YDL1 (0x02)
-#define VFC_SAA9051_YDL2 (0x04)
-#define VFC_SAA9051_SS2 (0x08)
-#define VFC_SAA9051_SS3 (0x10)
-#define VFC_SAA9051_YC (0x20)
-#define VFC_SAA9051_CT (0x40)
-#define VFC_SAA9051_SYC (0x80)
-
-
-#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1])
-#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\
- (a)->saa9051_state_array,\
- VFC_SAA9051_NR))
-
-
-struct vfc_dev {
- volatile struct vfc_regs __iomem *regs;
- struct vfc_regs *phys_regs;
- unsigned int control_reg;
- struct mutex device_lock_mtx;
- int instance;
- int busy;
- unsigned long which_io;
- unsigned char saa9051_state_array[VFC_SAA9051_NR];
-};
-
-void captstat_reset(struct vfc_dev *);
-void memptr_reset(struct vfc_dev *);
-
-int vfc_pcf8584_init(struct vfc_dev *);
-void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long);
-void vfc_i2c_delay(struct vfc_dev *);
-int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_reset_bus(struct vfc_dev *);
-int vfc_init_i2c_bus(struct vfc_dev *);
-
-#define VFC_CONTROL_DIAGMODE 0x10000000
-#define VFC_CONTROL_MEMPTR 0x20000000
-#define VFC_CONTROL_CAPTURE 0x02000000
-#define VFC_CONTROL_CAPTRESET 0x04000000
-
-#define VFC_STATUS_CAPTURE 0x08000000
-
-#ifdef VFC_IOCTL_DEBUG
-#define VFC_IOCTL_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_IOCTL_DEBUG_PRINTK(a)
-#endif
-
-#ifdef VFC_I2C_DEBUG
-#define VFC_I2C_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_I2C_DEBUG_PRINTK(a)
-#endif
-
-#endif /* _LINUX_VFC_H_ */
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
deleted file mode 100644
index 25181bb7d62..00000000000
--- a/drivers/sbus/char/vfc_dev.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * drivers/sbus/char/vfc_dev.c
- *
- * Driver for the Videopix Frame Grabber.
- *
- * In order to use the VFC you need to program the video controller
- * chip. This chip is the Phillips SAA9051. You need to call their
- * documentation ordering line to get the docs.
- *
- * There is very little documentation on the VFC itself. There is
- * some useful info that can be found in the manuals that come with
- * the card. I will hopefully write some better docs at a later date.
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- * */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#define VFC_MAJOR (60)
-
-#if 0
-#define VFC_IOCTL_DEBUG
-#endif
-
-#include "vfc.h"
-#include <asm/vfc_ioctls.h>
-
-static const struct file_operations vfc_fops;
-static struct vfc_dev **vfc_dev_lst;
-static char vfcstr[]="vfc";
-static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
- 0x00, 0x64, 0x72, 0x52,
- 0x36, 0x18, 0xff, 0x20,
- 0xfc, 0x77, 0xe3, 0x50,
- 0x3e
-};
-
-static void vfc_lock_device(struct vfc_dev *dev)
-{
- mutex_lock(&dev->device_lock_mtx);
-}
-
-static void vfc_unlock_device(struct vfc_dev *dev)
-{
- mutex_unlock(&dev->device_lock_mtx);
-}
-
-
-static void vfc_captstat_reset(struct vfc_dev *dev)
-{
- dev->control_reg |= VFC_CONTROL_CAPTRESET;
- sbus_writel(dev->control_reg, &dev->regs->control);
- dev->control_reg &= ~VFC_CONTROL_CAPTRESET;
- sbus_writel(dev->control_reg, &dev->regs->control);
- dev->control_reg |= VFC_CONTROL_CAPTRESET;
- sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static void vfc_memptr_reset(struct vfc_dev *dev)
-{
- dev->control_reg |= VFC_CONTROL_MEMPTR;
- sbus_writel(dev->control_reg, &dev->regs->control);
- dev->control_reg &= ~VFC_CONTROL_MEMPTR;
- sbus_writel(dev->control_reg, &dev->regs->control);
- dev->control_reg |= VFC_CONTROL_MEMPTR;
- sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static int vfc_csr_init(struct vfc_dev *dev)
-{
- dev->control_reg = 0x80000000;
- sbus_writel(dev->control_reg, &dev->regs->control);
- udelay(200);
- dev->control_reg &= ~0x80000000;
- sbus_writel(dev->control_reg, &dev->regs->control);
- udelay(100);
- sbus_writel(0x0f000000, &dev->regs->i2c_magic2);
-
- vfc_memptr_reset(dev);
-
- dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
- dev->control_reg &= ~VFC_CONTROL_CAPTURE;
- dev->control_reg |= 0x40000000;
- sbus_writel(dev->control_reg, &dev->regs->control);
-
- vfc_captstat_reset(dev);
-
- return 0;
-}
-
-static int vfc_saa9051_init(struct vfc_dev *dev)
-{
- int i;
-
- for (i = 0; i < VFC_SAA9051_NR; i++)
- dev->saa9051_state_array[i] = saa9051_init_array[i];
-
- vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR,
- dev->saa9051_state_array, VFC_SAA9051_NR);
- return 0;
-}
-
-static int init_vfc_hw(struct vfc_dev *dev)
-{
- vfc_lock_device(dev);
- vfc_csr_init(dev);
-
- vfc_pcf8584_init(dev);
- vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic
- sun code above*/
- vfc_saa9051_init(dev);
- vfc_unlock_device(dev);
- return 0;
-}
-
-static int init_vfc_devstruct(struct vfc_dev *dev, int instance)
-{
- dev->instance=instance;
- mutex_init(&dev->device_lock_mtx);
- dev->control_reg=0;
- dev->busy=0;
- return 0;
-}
-
-static int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev,
- int instance)
-{
- if(dev == NULL) {
- printk(KERN_ERR "VFC: Bogus pointer passed\n");
- return -ENOMEM;
- }
- printk("Initializing vfc%d\n",instance);
- dev->regs = NULL;
- dev->regs = (volatile struct vfc_regs __iomem *)
- sbus_ioremap(&sdev->resource[0], 0,
- sizeof(struct vfc_regs), vfcstr);
- dev->which_io = sdev->reg_addrs[0].which_io;
- dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr;
- if (dev->regs == NULL)
- return -EIO;
-
- printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n",
- instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
-
- if (init_vfc_devstruct(dev, instance))
- return -EINVAL;
- if (init_vfc_hw(dev))
- return -EIO;
- return 0;
-}
-
-
-static struct vfc_dev *vfc_get_dev_ptr(int instance)
-{
- return vfc_dev_lst[instance];
-}
-
-static DEFINE_SPINLOCK(vfc_dev_lock);
-
-static int vfc_open(struct inode *inode, struct file *file)
-{
- struct vfc_dev *dev;
-
- lock_kernel();
- spin_lock(&vfc_dev_lock);
- dev = vfc_get_dev_ptr(iminor(inode));
- if (dev == NULL) {
- spin_unlock(&vfc_dev_lock);
- unlock_kernel();
- return -ENODEV;
- }
- if (dev->busy) {
- spin_unlock(&vfc_dev_lock);
- unlock_kernel();
- return -EBUSY;
- }
-
- dev->busy = 1;
- spin_unlock(&vfc_dev_lock);
-
- vfc_lock_device(dev);
-
- vfc_csr_init(dev);
- vfc_pcf8584_init(dev);
- vfc_init_i2c_bus(dev);
- vfc_saa9051_init(dev);
- vfc_memptr_reset(dev);
- vfc_captstat_reset(dev);
-
- vfc_unlock_device(dev);
- unlock_kernel();
- return 0;
-}
-
-static int vfc_release(struct inode *inode,struct file *file)
-{
- struct vfc_dev *dev;
-
- spin_lock(&vfc_dev_lock);
- dev = vfc_get_dev_ptr(iminor(inode));
- if (!dev || !dev->busy) {
- spin_unlock(&vfc_dev_lock);
- return -EINVAL;
- }
- dev->busy = 0;
- spin_unlock(&vfc_dev_lock);
- return 0;
-}
-
-static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp)
-{
- struct vfc_debug_inout inout;
- unsigned char *buffer;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- switch(cmd) {
- case VFC_I2C_SEND:
- if(copy_from_user(&inout, argp, sizeof(inout)))
- return -EFAULT;
-
- buffer = kmalloc(inout.len, GFP_KERNEL);
- if (buffer == NULL)
- return -ENOMEM;
-
- if(copy_from_user(buffer, inout.buffer, inout.len)) {
- kfree(buffer);
- return -EFAULT;
- }
-
-
- vfc_lock_device(dev);
- inout.ret=
- vfc_i2c_sendbuf(dev,inout.addr & 0xff,
- buffer,inout.len);
-
- if (copy_to_user(argp,&inout,sizeof(inout))) {
- vfc_unlock_device(dev);
- kfree(buffer);
- return -EFAULT;
- }
- vfc_unlock_device(dev);
-
- break;
- case VFC_I2C_RECV:
- if (copy_from_user(&inout, argp, sizeof(inout)))
- return -EFAULT;
-
- buffer = kzalloc(inout.len, GFP_KERNEL);
- if (buffer == NULL)
- return -ENOMEM;
-
- vfc_lock_device(dev);
- inout.ret=
- vfc_i2c_recvbuf(dev,inout.addr & 0xff
- ,buffer,inout.len);
- vfc_unlock_device(dev);
-
- if (copy_to_user(inout.buffer, buffer, inout.len)) {
- kfree(buffer);
- return -EFAULT;
- }
- if (copy_to_user(argp,&inout,sizeof(inout))) {
- kfree(buffer);
- return -EFAULT;
- }
- kfree(buffer);
- break;
- default:
- return -EINVAL;
- };
-
- return 0;
-}
-
-static int vfc_capture_start(struct vfc_dev *dev)
-{
- vfc_captstat_reset(dev);
- dev->control_reg = sbus_readl(&dev->regs->control);
- if((dev->control_reg & VFC_STATUS_CAPTURE)) {
- printk(KERN_ERR "vfc%d: vfc capture status not reset\n",
- dev->instance);
- return -EIO;
- }
-
- vfc_lock_device(dev);
- dev->control_reg &= ~VFC_CONTROL_CAPTURE;
- sbus_writel(dev->control_reg, &dev->regs->control);
- dev->control_reg |= VFC_CONTROL_CAPTURE;
- sbus_writel(dev->control_reg, &dev->regs->control);
- dev->control_reg &= ~VFC_CONTROL_CAPTURE;
- sbus_writel(dev->control_reg, &dev->regs->control);
- vfc_unlock_device(dev);
-
- return 0;
-}
-
-static int vfc_capture_poll(struct vfc_dev *dev)
-{
- int timeout = 1000;
-
- while (!timeout--) {
- if (sbus_readl(&dev->regs->control) & VFC_STATUS_CAPTURE)
- break;
- vfc_i2c_delay_no_busy(dev, 100);
- }
- if(!timeout) {
- printk(KERN_WARNING "vfc%d: capture timed out\n",
- dev->instance);
- return -ETIMEDOUT;
- }
- return 0;
-}
-
-
-
-static int vfc_set_control_ioctl(struct inode *inode, struct file *file,
- struct vfc_dev *dev, unsigned long arg)
-{
- int setcmd, ret = 0;
-
- if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int)))
- return -EFAULT;
-
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
- dev->instance,setcmd));
-
- switch(setcmd) {
- case MEMPRST:
- vfc_lock_device(dev);
- vfc_memptr_reset(dev);
- vfc_unlock_device(dev);
- ret=0;
- break;
- case CAPTRCMD:
- vfc_capture_start(dev);
- vfc_capture_poll(dev);
- break;
- case DIAGMODE:
- if(capable(CAP_SYS_ADMIN)) {
- vfc_lock_device(dev);
- dev->control_reg |= VFC_CONTROL_DIAGMODE;
- sbus_writel(dev->control_reg, &dev->regs->control);
- vfc_unlock_device(dev);
- ret = 0;
- } else {
- ret = -EPERM;
- }
- break;
- case NORMMODE:
- vfc_lock_device(dev);
- dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
- sbus_writel(dev->control_reg, &dev->regs->control);
- vfc_unlock_device(dev);
- ret = 0;
- break;
- case CAPTRSTR:
- vfc_capture_start(dev);
- ret = 0;
- break;
- case CAPTRWAIT:
- vfc_capture_poll(dev);
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- break;
- };
-
- return ret;
-}
-
-
-static int vfc_port_change_ioctl(struct inode *inode, struct file *file,
- struct vfc_dev *dev, unsigned long arg)
-{
- int ret = 0;
- int cmd;
-
- if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
- "vfc_port_change_ioctl\n",
- dev->instance));
- return -EFAULT;
- }
-
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
- dev->instance, cmd));
-
- switch(cmd) {
- case 1:
- case 2:
- VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2;
- VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3;
- VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e;
- break;
- case 3:
- VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) =
- VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2;
- VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC;
- VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0;
- VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
- ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
- break;
- default:
- ret = -EINVAL;
- return ret;
- break;
- }
-
- switch(cmd) {
- case 1:
- VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |=
- (VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
- break;
- case 2:
- VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
- ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
- VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0;
- break;
- case 3:
- break;
- default:
- ret = -EINVAL;
- return ret;
- break;
- }
- VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2);
- ret=vfc_update_saa9051(dev);
- udelay(500);
- VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2);
- ret=vfc_update_saa9051(dev);
- return ret;
-}
-
-static int vfc_set_video_ioctl(struct inode *inode, struct file *file,
- struct vfc_dev *dev, unsigned long arg)
-{
- int ret = 0;
- int cmd;
-
- if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
- "vfc_set_video_ioctl\n",
- dev->instance));
- return ret;
- }
-
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
- dev->instance, cmd));
- switch(cmd) {
- case STD_NTSC:
- VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT;
- VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN |
- VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS;
- ret = vfc_update_saa9051(dev);
- break;
- case STD_PAL:
- VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN |
- VFC_SAA9051_CCFR1 |
- VFC_SAA9051_CCFR0 |
- VFC_SAA9051_FS);
- VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT;
- ret = vfc_update_saa9051(dev);
- break;
-
- case COLOR_ON:
- VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO;
- VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &=
- ~(VFC_SAA9051_BY | VFC_SAA9051_PF);
- ret = vfc_update_saa9051(dev);
- break;
- case MONO:
- VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO);
- VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |=
- (VFC_SAA9051_BY | VFC_SAA9051_PF);
- ret = vfc_update_saa9051(dev);
- break;
- default:
- ret = -EINVAL;
- break;
- };
-
- return ret;
-}
-
-static int vfc_get_video_ioctl(struct inode *inode, struct file *file,
- struct vfc_dev *dev, unsigned long arg)
-{
- int ret = 0;
- unsigned int status = NO_LOCK;
- unsigned char buf[1];
-
- if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) {
- printk(KERN_ERR "vfc%d: Unable to get status\n",
- dev->instance);
- return -EIO;
- }
-
- if(buf[0] & VFC_SAA9051_HLOCK) {
- status = NO_LOCK;
- } else if(buf[0] & VFC_SAA9051_FD) {
- if(buf[0] & VFC_SAA9051_CD)
- status = NTSC_COLOR;
- else
- status = NTSC_NOCOLOR;
- } else {
- if(buf[0] & VFC_SAA9051_CD)
- status = PAL_COLOR;
- else
- status = PAL_NOCOLOR;
- }
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; "
- "buf[0]=%x\n", dev->instance, status, buf[0]));
-
- if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) {
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
- "vfc_get_video_ioctl\n",
- dev->instance));
- return ret;
- }
- return ret;
-}
-
-static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret = 0;
- unsigned int tmp;
- struct vfc_dev *dev;
- void __user *argp = (void __user *)arg;
-
- dev = vfc_get_dev_ptr(iminor(inode));
- if(dev == NULL)
- return -ENODEV;
-
- switch(cmd & 0x0000ffff) {
- case VFCGCTRL:
-#if 0
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance));
-#endif
- tmp = sbus_readl(&dev->regs->control);
- if(copy_to_user(argp, &tmp, sizeof(unsigned int))) {
- ret = -EFAULT;
- break;
- }
- ret = 0;
- break;
- case VFCSCTRL:
- ret = vfc_set_control_ioctl(inode, file, dev, arg);
- break;
- case VFCGVID:
- ret = vfc_get_video_ioctl(inode, file, dev, arg);
- break;
- case VFCSVID:
- ret = vfc_set_video_ioctl(inode, file, dev, arg);
- break;
- case VFCHUE:
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance));
- if(copy_from_user(&tmp,argp,sizeof(unsigned int))) {
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
- "to IOCTL(VFCHUE)", dev->instance));
- ret = -EFAULT;
- } else {
- VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp;
- vfc_update_saa9051(dev);
- ret = 0;
- }
- break;
- case VFCPORTCHG:
- ret = vfc_port_change_ioctl(inode, file, dev, arg);
- break;
- case VFCRDINFO:
- ret = -EINVAL;
- VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance));
- break;
- default:
- ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp);
- break;
- };
-
- return ret;
-}
-
-static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
-{
- unsigned int map_size, ret, map_offset;
- struct vfc_dev *dev;
-
- dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode));
- if(dev == NULL)
- return -ENODEV;
-
- map_size = vma->vm_end - vma->vm_start;
- if(map_size > sizeof(struct vfc_regs))
- map_size = sizeof(struct vfc_regs);
-
- vma->vm_flags |=
- (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
- map_offset = (unsigned int) (long)dev->phys_regs;
- ret = io_remap_pfn_range(vma, vma->vm_start,
- MK_IOSPACE_PFN(dev->which_io,
- map_offset >> PAGE_SHIFT),
- map_size, vma->vm_page_prot);
-
- if(ret)
- return -EAGAIN;
-
- return 0;
-}
-
-
-static const struct file_operations vfc_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = vfc_ioctl,
- .mmap = vfc_mmap,
- .open = vfc_open,
- .release = vfc_release,
-};
-
-static int vfc_probe(void)
-{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
- int ret;
- int instance = 0, cards = 0;
-
- for_all_sbusdev(sdev, sbus) {
- if (strcmp(sdev->prom_name, "vfc") == 0) {
- cards++;
- continue;
- }
- }
-
- if (!cards)
- return -ENODEV;
-
- vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
- if (vfc_dev_lst == NULL)
- return -ENOMEM;
- vfc_dev_lst[cards] = NULL;
-
- ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
- if(ret) {
- printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR);
- kfree(vfc_dev_lst);
- return -EIO;
- }
- instance = 0;
- for_all_sbusdev(sdev, sbus) {
- if (strcmp(sdev->prom_name, "vfc") == 0) {
- vfc_dev_lst[instance]=(struct vfc_dev *)
- kmalloc(sizeof(struct vfc_dev), GFP_KERNEL);
- if (vfc_dev_lst[instance] == NULL)
- return -ENOMEM;
- ret = init_vfc_device(sdev,
- vfc_dev_lst[instance],
- instance);
- if(ret) {
- printk(KERN_ERR "Unable to initialize"
- " vfc%d device\n",
- instance);
- } else {
- }
-
- instance++;
- continue;
- }
- }
-
- return 0;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int vfc_init(void)
-#endif
-{
- return vfc_probe();
-}
-
-#ifdef MODULE
-static void deinit_vfc_device(struct vfc_dev *dev)
-{
- if(dev == NULL)
- return;
- sbus_iounmap(dev->regs, sizeof(struct vfc_regs));
- kfree(dev);
-}
-
-void cleanup_module(void)
-{
- struct vfc_dev **devp;
-
- unregister_chrdev(VFC_MAJOR,vfcstr);
-
- for (devp = vfc_dev_lst; *devp; devp++)
- deinit_vfc_device(*devp);
-
- kfree(vfc_dev_lst);
- return;
-}
-#endif
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
deleted file mode 100644
index 32b986e0ed7..00000000000
--- a/drivers/sbus/char/vfc_i2c.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * drivers/sbus/char/vfc_i2c.c
- *
- * Driver for the Videopix Frame Grabber.
- *
- * Functions that support the Phillips i2c(I squared C) bus on the vfc
- * Documentation for the Phillips I2C bus can be found on the
- * phillips home page
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- *
- */
-
-/* NOTE: It seems to me that the documentation regarding the
-pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
-Based on the information on the I2C bus itself and the remainder of
-the Phillips docs the following algorithms appear to be correct. I am
-fairly certain that the flowcharts in the phillips docs are wrong. */
-
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-
-#if 0
-#define VFC_I2C_DEBUG
-#endif
-
-#include "vfc.h"
-#include "vfc_i2c.h"
-
-#define WRITE_S1(__val) \
- sbus_writel(__val, &dev->regs->i2c_s1)
-#define WRITE_REG(__val) \
- sbus_writel(__val, &dev->regs->i2c_reg)
-
-#define VFC_I2C_READ (0x1)
-#define VFC_I2C_WRITE (0x0)
-
-/******
- The i2c bus controller chip on the VFC is a pcd8584t, but
- phillips claims it doesn't exist. As far as I can tell it is
- identical to the PCF8584 so I treat it like it is the pcf8584.
-
- NOTE: The pcf8584 only cares
- about the msb of the word you feed it
-*****/
-
-int vfc_pcf8584_init(struct vfc_dev *dev)
-{
- /* This will also choose register S0_OWN so we can set it. */
- WRITE_S1(RESET);
-
- /* The pcf8584 shifts this value left one bit and uses
- * it as its i2c bus address.
- */
- WRITE_REG(0x55000000);
-
- /* This will set the i2c bus at the same speed sun uses,
- * and set another magic bit.
- */
- WRITE_S1(SELECT(S2));
- WRITE_REG(0x14000000);
-
- /* Enable the serial port, idle the i2c bus and set
- * the data reg to s0.
- */
- WRITE_S1(CLEAR_I2C_BUS);
- udelay(100);
- return 0;
-}
-
-void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs)
-{
- schedule_timeout_uninterruptible(usecs_to_jiffies(usecs));
-}
-
-void inline vfc_i2c_delay(struct vfc_dev *dev)
-{
- vfc_i2c_delay_no_busy(dev, 100);
-}
-
-int vfc_init_i2c_bus(struct vfc_dev *dev)
-{
- WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK);
- vfc_i2c_reset_bus(dev);
- return 0;
-}
-
-int vfc_i2c_reset_bus(struct vfc_dev *dev)
-{
- VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
- dev->instance));
- if(dev == NULL)
- return -EINVAL;
- if(dev->regs == NULL)
- return -EINVAL;
- WRITE_S1(SEND_I2C_STOP);
- WRITE_S1(SEND_I2C_STOP | ACK);
- vfc_i2c_delay(dev);
- WRITE_S1(CLEAR_I2C_BUS);
- VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
- dev->instance,
- sbus_readl(&dev->regs->i2c_s1)));
- return 0;
-}
-
-static int vfc_i2c_wait_for_bus(struct vfc_dev *dev)
-{
- int timeout = 1000;
-
- while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) {
- if(!(timeout--))
- return -ETIMEDOUT;
- vfc_i2c_delay(dev);
- }
- return 0;
-}
-
-static int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack)
-{
- int timeout = 1000;
- int s1;
-
- while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) {
- if (!(timeout--))
- return -ETIMEDOUT;
- vfc_i2c_delay(dev);
- }
- if (ack == VFC_I2C_ACK_CHECK) {
- if(s1 & LRB)
- return -EIO;
- }
- return 0;
-}
-
-#define SHIFT(a) ((a) << 24)
-static int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr,
- char mode)
-{
- int ret, raddr;
-#if 1
- WRITE_S1(SEND_I2C_STOP | ACK);
- WRITE_S1(SELECT(S0) | ENABLE_SERIAL);
- vfc_i2c_delay(dev);
-#endif
-
- switch(mode) {
- case VFC_I2C_READ:
- raddr = SHIFT(((unsigned int)addr | 0x1));
- WRITE_REG(raddr);
- VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n",
- dev->instance, addr | 0x1));
- break;
- case VFC_I2C_WRITE:
- raddr = SHIFT((unsigned int)addr & ~0x1);
- WRITE_REG(raddr);
- VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
- dev->instance, addr & ~0x1));
- break;
- default:
- return -EINVAL;
- };
-
- WRITE_S1(SEND_I2C_START);
- vfc_i2c_delay(dev);
- ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait
- for the
- i2c send
- to finish
- here but
- Sun
- doesn't,
- hmm */
- if (ret) {
- printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n",
- dev->instance);
- return ret;
- } else if (mode == VFC_I2C_READ) {
- if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) {
- printk(KERN_WARNING
- "vfc%d: returned slave address "
- "mismatch(%x,%x)\n",
- dev->instance, raddr, ret);
- }
- }
- return 0;
-}
-
-static int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte)
-{
- int ret;
- u32 val = SHIFT((unsigned int)*byte);
-
- WRITE_REG(val);
-
- ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK);
- switch(ret) {
- case -ETIMEDOUT:
- printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n",
- dev->instance);
- break;
- case -EIO:
- ret = XMIT_LAST_BYTE;
- break;
- default:
- break;
- };
-
- return ret;
-}
-
-static int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte,
- int last)
-{
- int ret;
-
- if (last) {
- WRITE_REG(NEGATIVE_ACK);
- VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
- dev->instance));
- } else {
- WRITE_S1(ACK);
- }
-
- ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK);
- if(ret) {
- printk(KERN_ERR "vfc%d: "
- "VFC recv byte timed out\n",
- dev->instance);
- }
- *byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24;
- return ret;
-}
-
-int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
- char *buf, int count)
-{
- int ret, last;
-
- if(!(count && buf && dev && dev->regs) )
- return -EINVAL;
-
- if ((ret = vfc_i2c_wait_for_bus(dev))) {
- printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
- return ret;
- }
-
- if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) {
- WRITE_S1(SEND_I2C_STOP);
- vfc_i2c_delay(dev);
- return ret;
- }
-
- last = 0;
- while (count--) {
- if (!count)
- last = 1;
- if ((ret = vfc_i2c_recv_byte(dev, buf, last))) {
- printk(KERN_ERR "vfc%d: "
- "VFC error while receiving byte\n",
- dev->instance);
- WRITE_S1(SEND_I2C_STOP);
- ret = -EINVAL;
- }
- buf++;
- }
- WRITE_S1(SEND_I2C_STOP | ACK);
- vfc_i2c_delay(dev);
- return ret;
-}
-
-int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr,
- char *buf, int count)
-{
- int ret;
-
- if (!(buf && dev && dev->regs))
- return -EINVAL;
-
- if ((ret = vfc_i2c_wait_for_bus(dev))) {
- printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
- return ret;
- }
-
- if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) {
- WRITE_S1(SEND_I2C_STOP);
- vfc_i2c_delay(dev);
- return ret;
- }
-
- while(count--) {
- ret = vfc_i2c_xmit_byte(dev, buf);
- switch(ret) {
- case XMIT_LAST_BYTE:
- VFC_I2C_DEBUG_PRINTK(("vfc%d: "
- "Receiver ended transmission with "
- " %d bytes remaining\n",
- dev->instance, count));
- ret = 0;
- goto done;
- break;
- case 0:
- break;
- default:
- printk(KERN_ERR "vfc%d: "
- "VFC error while sending byte\n", dev->instance);
- break;
- };
-
- buf++;
- }
-done:
- WRITE_S1(SEND_I2C_STOP | ACK);
- vfc_i2c_delay(dev);
- return ret;
-}
-
-
-
-
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h
deleted file mode 100644
index a2e6973209d..00000000000
--- a/drivers/sbus/char/vfc_i2c.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _LINUX_VFC_I2C_H_
-#define _LINUX_VFC_I2C_H_
-
-/* control bits */
-#define PIN (0x80000000)
-#define ESO (0x40000000)
-#define ES1 (0x20000000)
-#define ES2 (0x10000000)
-#define ENI (0x08000000)
-#define STA (0x04000000)
-#define STO (0x02000000)
-#define ACK (0x01000000)
-
-/* status bits */
-#define STS (0x20000000)
-#define BER (0x10000000)
-#define LRB (0x08000000)
-#define AAS (0x04000000)
-#define LAB (0x02000000)
-#define BB (0x01000000)
-
-#define SEND_I2C_START (PIN | ESO | STA)
-#define SEND_I2C_STOP (PIN | ESO | STO)
-#define CLEAR_I2C_BUS (PIN | ESO | ACK)
-#define NEGATIVE_ACK ((ESO) & ~ACK)
-
-#define SELECT(a) (a)
-#define S0 (PIN | ESO | ES1)
-#define S0_OWN (PIN)
-#define S2 (PIN | ES1)
-#define S3 (PIN | ES2)
-
-#define ENABLE_SERIAL (PIN | ESO)
-#define DISABLE_SERIAL (PIN)
-#define RESET (PIN)
-
-#define XMIT_LAST_BYTE (1)
-#define VFC_I2C_ACK_CHECK (1)
-#define VFC_I2C_NO_ACK_CHECK (0)
-
-#endif /* _LINUX_VFC_I2C_H_ */
-
-
-
diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
deleted file mode 100644
index ab0d2de3324..00000000000
--- a/drivers/sbus/dvma.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* dvma.c: Routines that are used to access DMA on the Sparc SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/sbus.h>
-
-struct sbus_dma *dma_chain;
-
-static void __init init_one_dvma(struct sbus_dma *dma, int num_dma)
-{
- printk("dma%d: ", num_dma);
-
- dma->next = NULL;
- dma->running = 0; /* No transfers going on as of yet */
- dma->allocated = 0; /* No one has allocated us yet */
- switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) {
- case DMA_VERS0:
- dma->revision = dvmarev0;
- printk("Revision 0 ");
- break;
- case DMA_ESCV1:
- dma->revision = dvmaesc1;
- printk("ESC Revision 1 ");
- break;
- case DMA_VERS1:
- dma->revision = dvmarev1;
- printk("Revision 1 ");
- break;
- case DMA_VERS2:
- dma->revision = dvmarev2;
- printk("Revision 2 ");
- break;
- case DMA_VERHME:
- dma->revision = dvmahme;
- printk("HME DVMA gate array ");
- break;
- case DMA_VERSPLUS:
- dma->revision = dvmarevplus;
- printk("Revision 1 PLUS ");
- break;
- default:
- printk("unknown dma version %08x",
- sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID);
- dma->allocated = 1;
- break;
- }
- printk("\n");
-}
-
-/* Probe this SBus DMA module(s) */
-void __init dvma_init(struct sbus_bus *sbus)
-{
- struct sbus_dev *this_dev;
- struct sbus_dma *dma;
- struct sbus_dma *dchain;
- static int num_dma = 0;
-
- for_each_sbusdev(this_dev, sbus) {
- char *name = this_dev->prom_name;
- int hme = 0;
-
- if(!strcmp(name, "SUNW,fas"))
- hme = 1;
- else if(strcmp(name, "dma") &&
- strcmp(name, "ledma") &&
- strcmp(name, "espdma"))
- continue;
-
- /* Found one... */
- dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
- dma->sdev = this_dev;
-
- /* Put at end of dma chain */
- dchain = dma_chain;
- if(dchain) {
- while(dchain->next)
- dchain = dchain->next;
- dchain->next = dma;
- } else {
- /* We're the first in line */
- dma_chain = dma;
- }
-
- dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0,
- dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1,
- "dma");
-
- dma->node = dma->sdev->prom_node;
-
- init_one_dvma(dma, num_dma++);
- }
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-
-void __init sun4_dvma_init(void)
-{
- struct sbus_dma *dma;
- struct resource r;
-
- if(sun4_dma_physaddr) {
- dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
- /* No SBUS */
- dma->sdev = NULL;
-
- /* Only one DMA device */
- dma_chain = dma;
-
- memset(&r, 0, sizeof(r));
- r.start = sun4_dma_physaddr;
- dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma");
-
- /* No prom node */
- dma->node = 0x0;
-
- init_one_dvma(dma, 0);
- } else {
- dma_chain = NULL;
- }
-}
-
-#endif
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
deleted file mode 100644
index 9c129248466..00000000000
--- a/drivers/sbus/sbus.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* sbus.c: SBus support routines.
- *
- * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-
-static ssize_t
-show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
-{
- struct sbus_dev *sbus;
-
- sbus = to_sbus_device(dev);
-
- return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name);
-}
-
-static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL);
-
-struct sbus_bus *sbus_root;
-
-static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
-{
- struct dev_archdata *sd;
- unsigned long base;
- const void *pval;
- int len, err;
-
- sdev->prom_node = dp->node;
- strcpy(sdev->prom_name, dp->name);
-
- pval = of_get_property(dp, "reg", &len);
- sdev->num_registers = 0;
- if (pval) {
- memcpy(sdev->reg_addrs, pval, len);
-
- sdev->num_registers =
- len / sizeof(struct linux_prom_registers);
-
- base = (unsigned long) sdev->reg_addrs[0].phys_addr;
-
- /* Compute the slot number. */
- if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
- sdev->slot = sbus_dev_slot(base);
- else
- sdev->slot = sdev->reg_addrs[0].which_io;
- }
-
- pval = of_get_property(dp, "ranges", &len);
- sdev->num_device_ranges = 0;
- if (pval) {
- memcpy(sdev->device_ranges, pval, len);
- sdev->num_device_ranges =
- len / sizeof(struct linux_prom_ranges);
- }
-
- sbus_fill_device_irq(sdev);
-
- sd = &sdev->ofdev.dev.archdata;
- sd->prom_node = dp;
- sd->op = &sdev->ofdev;
-
- sdev->ofdev.node = dp;
- if (sdev->parent)
- sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
- else
- sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
- sdev->ofdev.dev.bus = &sbus_bus_type;
- dev_set_name(&sdev->ofdev.dev, "sbus[%08x]", dp->node);
-
- if (of_device_register(&sdev->ofdev) != 0)
- printk(KERN_DEBUG "sbus: device registration error for %s!\n",
- dp->path_component_name);
-
- /* WE HAVE BEEN INVADED BY ALIENS! */
- err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr);
-}
-
-static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
-{
- const void *pval;
- int len;
-
- pval = of_get_property(dp, "ranges", &len);
- sbus->num_sbus_ranges = 0;
- if (pval) {
- memcpy(sbus->sbus_ranges, pval, len);
- sbus->num_sbus_ranges =
- len / sizeof(struct linux_prom_ranges);
-
- sbus_arch_bus_ranges_init(dp->parent, sbus);
- }
-}
-
-static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
- int num_ranges,
- struct linux_prom_registers *regs,
- int num_regs)
-{
- if (num_ranges) {
- int regnum;
-
- for (regnum = 0; regnum < num_regs; regnum++) {
- int rngnum;
-
- for (rngnum = 0; rngnum < num_ranges; rngnum++) {
- if (regs[regnum].which_io == ranges[rngnum].ot_child_space)
- break;
- }
- if (rngnum == num_ranges) {
- /* We used to flag this as an error. Actually
- * some devices do not report the regs as we expect.
- * For example, see SUNW,pln device. In that case
- * the reg property is in a format internal to that
- * node, ie. it is not in the SBUS register space
- * per se. -DaveM
- */
- return;
- }
- regs[regnum].which_io = ranges[rngnum].ot_parent_space;
- regs[regnum].phys_addr -= ranges[rngnum].ot_child_base;
- regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;
- }
- }
-}
-
-static void __init __fixup_regs_sdev(struct sbus_dev *sdev)
-{
- if (sdev->num_registers != 0) {
- struct sbus_dev *parent = sdev->parent;
- int i;
-
- while (parent != NULL) {
- __apply_ranges_to_regs(parent->device_ranges,
- parent->num_device_ranges,
- sdev->reg_addrs,
- sdev->num_registers);
-
- parent = parent->parent;
- }
-
- __apply_ranges_to_regs(sdev->bus->sbus_ranges,
- sdev->bus->num_sbus_ranges,
- sdev->reg_addrs,
- sdev->num_registers);
-
- for (i = 0; i < sdev->num_registers; i++) {
- struct resource *res = &sdev->resource[i];
-
- res->start = sdev->reg_addrs[i].phys_addr;
- res->end = (res->start +
- (unsigned long)sdev->reg_addrs[i].reg_size - 1UL);
- res->flags = IORESOURCE_IO |
- (sdev->reg_addrs[i].which_io & 0xff);
- }
- }
-}
-
-static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
-{
- struct sbus_dev *sdev;
-
- for (sdev = first_sdev; sdev; sdev = sdev->next) {
- if (sdev->child)
- sbus_fixup_all_regs(sdev->child);
- __fixup_regs_sdev(sdev);
- }
-}
-
-/* We preserve the "probe order" of these bus and device lists to give
- * the same ordering as the old code.
- */
-static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
-{
- while (*root)
- root = &(*root)->next;
- *root = sbus;
- sbus->next = NULL;
-}
-
-static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
-{
- while (*root)
- root = &(*root)->next;
- *root = sdev;
- sdev->next = NULL;
-}
-
-static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
-{
- dp = dp->child;
- while (dp) {
- struct sbus_dev *sdev;
-
- sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
- if (sdev) {
- sdev_insert(sdev, &parent->child);
-
- sdev->bus = sbus;
- sdev->parent = parent;
- sdev->ofdev.dev.archdata.iommu =
- sbus->ofdev.dev.archdata.iommu;
- sdev->ofdev.dev.archdata.stc =
- sbus->ofdev.dev.archdata.stc;
-
- fill_sbus_device(dp, sdev);
-
- walk_children(dp, sdev, sbus);
- }
- dp = dp->sibling;
- }
-}
-
-static void __init build_one_sbus(struct device_node *dp, int num_sbus)
-{
- struct sbus_bus *sbus;
- unsigned int sbus_clock;
- struct device_node *dev_dp;
-
- sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
- if (!sbus)
- return;
-
- sbus_insert(sbus, &sbus_root);
- sbus->prom_node = dp->node;
-
- sbus_setup_iommu(sbus, dp);
-
- printk("sbus%d: ", num_sbus);
-
- sbus_clock = of_getintprop_default(dp, "clock-frequency",
- (25*1000*1000));
- sbus->clock_freq = sbus_clock;
-
- printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
- (int) (((sbus_clock/1000)%1000 != 0) ?
- (((sbus_clock/1000)%1000) + 1000) : 0));
-
- strcpy(sbus->prom_name, dp->name);
-
- sbus_setup_arch_props(sbus, dp);
-
- sbus_bus_ranges_init(dp, sbus);
-
- sbus->ofdev.node = dp;
- sbus->ofdev.dev.parent = NULL;
- sbus->ofdev.dev.bus = &sbus_bus_type;
- dev_set_name(&sbus->ofdev.dev, "sbus%d", num_sbus);
-
- if (of_device_register(&sbus->ofdev) != 0)
- printk(KERN_DEBUG "sbus: device registration error for %s!\n",
- dev_name(&sbus->ofdev.dev));
-
- dev_dp = dp->child;
- while (dev_dp) {
- struct sbus_dev *sdev;
-
- sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
- if (sdev) {
- sdev_insert(sdev, &sbus->devices);
-
- sdev->bus = sbus;
- sdev->parent = NULL;
- sdev->ofdev.dev.archdata.iommu =
- sbus->ofdev.dev.archdata.iommu;
- sdev->ofdev.dev.archdata.stc =
- sbus->ofdev.dev.archdata.stc;
-
- fill_sbus_device(dev_dp, sdev);
-
- walk_children(dev_dp, sdev, sbus);
- }
- dev_dp = dev_dp->sibling;
- }
-
- sbus_fixup_all_regs(sbus->devices);
-
- dvma_init(sbus);
-}
-
-static int __init sbus_init(void)
-{
- struct device_node *dp;
- const char *sbus_name = "sbus";
- int num_sbus = 0;
-
- if (sbus_arch_preinit())
- return 0;
-
- if (sparc_cpu_model == sun4d)
- sbus_name = "sbi";
-
- for_each_node_by_name(dp, sbus_name) {
- build_one_sbus(dp, num_sbus);
- num_sbus++;
-
- }
-
- sbus_arch_postinit();
-
- return 0;
-}
-
-subsys_initcall(sbus_init);
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index bb43a138818..28e22acf87e 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -521,7 +521,8 @@ struct esp {
struct completion *eh_reset;
- struct sbus_dma *dma;
+ void *dma;
+ int dmarev;
};
/* A front-end driver for the ESP chip should do the following in
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 90535089672..69d6ad862b6 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1,6 +1,6 @@
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
- * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net)
*
* A lot of this driver was directly stolen from Erik H. Moe's PCI
* Qlogic ISP driver. Mucho kudos to him for this code.
@@ -25,12 +25,14 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/jiffies.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/byteorder.h>
#include "qlogicpti.h"
-#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/ptrace.h>
@@ -157,7 +159,7 @@ static inline void set_sbus_cfg1(struct qlogicpti *qpti)
* is a nop and the chip ends up using the smallest burst
* size. -DaveM
*/
- if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) {
+ if (sbus_can_burst64() && (bursts & DMA_BURST64)) {
val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64);
} else
#endif
@@ -684,19 +686,19 @@ static void __devexit qpti_chain_del(struct qlogicpti *qpti)
static int __devinit qpti_map_regs(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
- qpti->qregs = sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "PTI Qlogic/ISP");
+ qpti->qregs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "PTI Qlogic/ISP");
if (!qpti->qregs) {
printk("PTI: Qlogic/ISP registers are unmappable\n");
return -1;
}
if (qpti->is_pti) {
- qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096),
- sizeof(unsigned char),
- "PTI Qlogic/ISP statreg");
+ qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096),
+ sizeof(unsigned char),
+ "PTI Qlogic/ISP statreg");
if (!qpti->sreg) {
printk("PTI: Qlogic/ISP status register is unmappable\n");
return -1;
@@ -707,9 +709,9 @@ static int __devinit qpti_map_regs(struct qlogicpti *qpti)
static int __devinit qpti_register_irq(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
- qpti->qhost->irq = qpti->irq = sdev->irqs[0];
+ qpti->qhost->irq = qpti->irq = op->irqs[0];
/* We used to try various overly-clever things to
* reduce the interrupt processing overhead on
@@ -732,17 +734,19 @@ fail:
static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
{
- qpti->scsi_id = prom_getintdefault(qpti->prom_node,
- "initiator-id",
- -1);
+ struct of_device *op = qpti->op;
+ struct device_node *dp;
+
+ dp = op->node;
+
+ qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1);
if (qpti->scsi_id == -1)
- qpti->scsi_id = prom_getintdefault(qpti->prom_node,
- "scsi-initiator-id",
- -1);
+ qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id",
+ -1);
if (qpti->scsi_id == -1)
qpti->scsi_id =
- prom_getintdefault(qpti->sdev->bus->prom_node,
- "scsi-initiator-id", 7);
+ of_getintprop_default(dp->parent,
+ "scsi-initiator-id", 7);
qpti->qhost->this_id = qpti->scsi_id;
qpti->qhost->max_sectors = 64;
@@ -751,12 +755,11 @@ static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
static void qpti_get_bursts(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
u8 bursts, bmask;
- bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff);
- bmask = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0xff);
+ bursts = of_getintprop_default(op->node, "burst-sizes", 0xff);
+ bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff);
if (bmask != 0xff)
bursts &= bmask;
if (bursts == 0xff ||
@@ -785,25 +788,25 @@ static void qpti_get_clock(struct qlogicpti *qpti)
*/
static int __devinit qpti_map_queues(struct qlogicpti *qpti)
{
- struct sbus_dev *sdev = qpti->sdev;
+ struct of_device *op = qpti->op;
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- qpti->res_cpu = sbus_alloc_consistent(sdev,
- QSIZE(RES_QUEUE_LEN),
- &qpti->res_dvma);
+ qpti->res_cpu = dma_alloc_coherent(&op->dev,
+ QSIZE(RES_QUEUE_LEN),
+ &qpti->res_dvma, GFP_ATOMIC);
if (qpti->res_cpu == NULL ||
qpti->res_dvma == 0) {
printk("QPTI: Cannot map response queue.\n");
return -1;
}
- qpti->req_cpu = sbus_alloc_consistent(sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- &qpti->req_dvma);
+ qpti->req_cpu = dma_alloc_coherent(&op->dev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ &qpti->req_dvma, GFP_ATOMIC);
if (qpti->req_cpu == NULL ||
qpti->req_dvma == 0) {
- sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
+ dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
printk("QPTI: Cannot map request queue.\n");
return -1;
}
@@ -875,8 +878,9 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
int sg_count;
sg = scsi_sglist(Cmnd);
- sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
- Cmnd->sc_data_direction);
+ sg_count = dma_map_sg(&qpti->op->dev, sg,
+ scsi_sg_count(Cmnd),
+ Cmnd->sc_data_direction);
ds = cmd->dataseg;
cmd->segment_cnt = sg_count;
@@ -1152,9 +1156,9 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
Cmnd->result = DID_ERROR << 16;
if (scsi_bufflen(Cmnd))
- sbus_unmap_sg(qpti->sdev,
- scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
- Cmnd->sc_data_direction);
+ dma_unmap_sg(&qpti->op->dev,
+ scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
+ Cmnd->sc_data_direction);
qpti->cmd_count[Cmnd->device->id]--;
sbus_writew(out_ptr, qpti->qregs + MBOX5);
@@ -1268,34 +1272,32 @@ static struct scsi_host_template qpti_template = {
.use_clustering = ENABLE_CLUSTERING,
};
-static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- static int nqptis;
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
struct scsi_host_template *tpnt = match->data;
+ struct device_node *dp = op->node;
struct Scsi_Host *host;
struct qlogicpti *qpti;
+ static int nqptis;
const char *fcode;
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
*/
- if (sdev->irqs[0] == 0)
+ if (op->irqs[0] == 0)
return -ENODEV;
host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
if (!host)
return -ENOMEM;
- qpti = (struct qlogicpti *) host->hostdata;
+ qpti = shost_priv(host);
host->max_id = MAX_TARGETS;
qpti->qhost = host;
- qpti->sdev = sdev;
+ qpti->op = op;
qpti->qpti_id = nqptis;
- qpti->prom_node = sdev->prom_node;
- strcpy(qpti->prom_name, sdev->ofdev.node->name);
+ strcpy(qpti->prom_name, op->node->name);
qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
if (qpti_map_regs(qpti) < 0)
@@ -1341,12 +1343,12 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
- if (scsi_add_host(host, &dev->dev)) {
+ if (scsi_add_host(host, &op->dev)) {
printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id);
goto fail_unmap_queues;
}
- dev_set_drvdata(&sdev->ofdev.dev, qpti);
+ dev_set_drvdata(&op->dev, qpti);
qpti_chain_add(qpti);
@@ -1357,19 +1359,20 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
+ dma_free_coherent(&op->dev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ dma_free_coherent(&op->dev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
fail_unmap_regs:
- sbus_iounmap(qpti->qregs,
- qpti->sdev->reg_addrs[0].reg_size);
+ of_iounmap(&op->resource[0], qpti->qregs,
+ resource_size(&op->resource[0]));
if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+ of_iounmap(&op->resource[0], qpti->sreg,
+ sizeof(unsigned char));
fail_free_irq:
free_irq(qpti->irq, qpti);
@@ -1380,9 +1383,9 @@ fail_unlink:
return -ENODEV;
}
-static int __devexit qpti_sbus_remove(struct of_device *dev)
+static int __devexit qpti_sbus_remove(struct of_device *op)
{
- struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+ struct qlogicpti *qpti = dev_get_drvdata(&op->dev);
qpti_chain_del(qpti);
@@ -1395,24 +1398,25 @@ static int __devexit qpti_sbus_remove(struct of_device *dev)
free_irq(qpti->irq, qpti);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
+ dma_free_coherent(&op->dev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ dma_free_coherent(&op->dev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
- sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+ of_iounmap(&op->resource[0], qpti->qregs,
+ resource_size(&op->resource[0]));
if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+ of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char));
scsi_host_put(qpti->qhost);
return 0;
}
-static struct of_device_id qpti_match[] = {
+static const struct of_device_id qpti_match[] = {
{
.name = "ptisp",
.data = &qpti_template,
@@ -1442,7 +1446,7 @@ static struct of_platform_driver qpti_sbus_driver = {
static int __init qpti_init(void)
{
- return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&qpti_sbus_driver, &of_bus_type);
}
static void __exit qpti_exit(void)
@@ -1453,7 +1457,7 @@ static void __exit qpti_exit(void)
MODULE_DESCRIPTION("QlogicISP SBUS driver");
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
module_init(qpti_init);
module_exit(qpti_exit);
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index ef6da2df584..9c053bbaa87 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -342,7 +342,7 @@ struct qlogicpti {
u_int req_in_ptr; /* index of next request slot */
u_int res_out_ptr; /* index of next result slot */
long send_marker; /* must we send a marker? */
- struct sbus_dev *sdev;
+ struct of_device *op;
unsigned long __pad;
int cmd_count[MAX_TARGETS];
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index f9cf7015136..3d73aad4bc8 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -1,6 +1,6 @@
/* sun_esp.c: ESP front-end for Sparc SBUS systems.
*
- * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -9,60 +9,70 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/sbus.h>
-
#include <scsi/scsi_host.h>
#include "esp_scsi.h"
#define DRV_MODULE_NAME "sun_esp"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_VERSION "1.000"
-#define DRV_MODULE_RELDATE "April 19, 2007"
+#define DRV_VERSION "1.100"
+#define DRV_MODULE_RELDATE "August 27, 2008"
#define dma_read32(REG) \
sbus_readl(esp->dma_regs + (REG))
#define dma_write32(VAL, REG) \
sbus_writel((VAL), esp->dma_regs + (REG))
-static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
-{
- struct sbus_dev *sdev = esp->dev;
- struct sbus_dma *dma;
+/* DVMA chip revisions */
+enum dvma_rev {
+ dvmarev0,
+ dvmaesc1,
+ dvmarev1,
+ dvmarev2,
+ dvmarev3,
+ dvmarevplus,
+ dvmahme
+};
- if (dma_sdev != NULL) {
- for_each_dvma(dma) {
- if (dma->sdev == dma_sdev)
- break;
- }
- } else {
- for_each_dvma(dma) {
- if (dma->sdev == NULL)
- break;
+static int __devinit esp_sbus_setup_dma(struct esp *esp,
+ struct of_device *dma_of)
+{
+ esp->dma = dma_of;
- /* If bus + slot are the same and it has the
- * correct OBP name, it's ours.
- */
- if (sdev->bus == dma->sdev->bus &&
- sdev->slot == dma->sdev->slot &&
- (!strcmp(dma->sdev->prom_name, "dma") ||
- !strcmp(dma->sdev->prom_name, "espdma")))
- break;
- }
- }
+ esp->dma_regs = of_ioremap(&dma_of->resource[0], 0,
+ resource_size(&dma_of->resource[0]),
+ "espdma");
+ if (!esp->dma_regs)
+ return -ENOMEM;
- if (dma == NULL) {
- printk(KERN_ERR PFX "[%s] Cannot find dma.\n",
- sdev->ofdev.node->full_name);
- return -ENODEV;
+ switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) {
+ case DMA_VERS0:
+ esp->dmarev = dvmarev0;
+ break;
+ case DMA_ESCV1:
+ esp->dmarev = dvmaesc1;
+ break;
+ case DMA_VERS1:
+ esp->dmarev = dvmarev1;
+ break;
+ case DMA_VERS2:
+ esp->dmarev = dvmarev2;
+ break;
+ case DMA_VERHME:
+ esp->dmarev = dvmahme;
+ break;
+ case DMA_VERSPLUS:
+ esp->dmarev = dvmarevplus;
+ break;
}
- esp->dma = dma;
- esp->dma_regs = dma->regs;
return 0;
@@ -70,18 +80,18 @@ static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sde
static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
{
- struct sbus_dev *sdev = esp->dev;
+ struct of_device *op = esp->dev;
struct resource *res;
/* On HME, two reg sets exist, first is DVMA,
* second is ESP registers.
*/
if (hme)
- res = &sdev->resource[1];
+ res = &op->resource[1];
else
- res = &sdev->resource[0];
+ res = &op->resource[0];
- esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+ esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
if (!esp->regs)
return -ENOMEM;
@@ -90,10 +100,11 @@ static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
static int __devinit esp_sbus_map_command_block(struct esp *esp)
{
- struct sbus_dev *sdev = esp->dev;
+ struct of_device *op = esp->dev;
- esp->command_block = sbus_alloc_consistent(sdev, 16,
- &esp->command_block_dma);
+ esp->command_block = dma_alloc_coherent(&op->dev, 16,
+ &esp->command_block_dma,
+ GFP_ATOMIC);
if (!esp->command_block)
return -ENOMEM;
return 0;
@@ -102,17 +113,18 @@ static int __devinit esp_sbus_map_command_block(struct esp *esp)
static int __devinit esp_sbus_register_irq(struct esp *esp)
{
struct Scsi_Host *host = esp->host;
- struct sbus_dev *sdev = esp->dev;
+ struct of_device *op = esp->dev;
- host->irq = sdev->irqs[0];
+ host->irq = op->irqs[0];
return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
}
-static void __devinit esp_get_scsi_id(struct esp *esp)
+static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
+ struct of_device *op = esp->dev;
+ struct device_node *dp;
+ dp = op->node;
esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
if (esp->scsi_id != 0xff)
goto done;
@@ -121,13 +133,7 @@ static void __devinit esp_get_scsi_id(struct esp *esp)
if (esp->scsi_id != 0xff)
goto done;
- if (!sdev->bus) {
- /* SUN4 */
- esp->scsi_id = 7;
- goto done;
- }
-
- esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+ esp->scsi_id = of_getintprop_default(espdma->node,
"scsi-initiator-id", 7);
done:
@@ -137,9 +143,10 @@ done:
static void __devinit esp_get_differential(struct esp *esp)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
+ struct of_device *op = esp->dev;
+ struct device_node *dp;
+ dp = op->node;
if (of_find_property(dp, "differential", NULL))
esp->flags |= ESP_FLAG_DIFFERENTIAL;
else
@@ -148,43 +155,36 @@ static void __devinit esp_get_differential(struct esp *esp)
static void __devinit esp_get_clock_params(struct esp *esp)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
- struct device_node *bus_dp;
+ struct of_device *op = esp->dev;
+ struct device_node *bus_dp, *dp;
int fmhz;
- bus_dp = NULL;
- if (sdev != NULL && sdev->bus != NULL)
- bus_dp = sdev->bus->ofdev.node;
+ dp = op->node;
+ bus_dp = dp->parent;
fmhz = of_getintprop_default(dp, "clock-frequency", 0);
if (fmhz == 0)
- fmhz = (!bus_dp) ? 0 :
- of_getintprop_default(bus_dp, "clock-frequency", 0);
+ fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0);
esp->cfreq = fmhz;
}
-static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of)
{
- struct sbus_dev *sdev = esp->dev;
- struct device_node *dp = sdev->ofdev.node;
- u8 bursts;
+ struct device_node *dma_dp = dma_of->node;
+ struct of_device *op = esp->dev;
+ struct device_node *dp;
+ u8 bursts, val;
+ dp = op->node;
bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
- if (dma) {
- struct device_node *dma_dp = dma->ofdev.node;
- u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
- if (val != 0xff)
- bursts &= val;
- }
+ val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
+ if (val != 0xff)
+ bursts &= val;
- if (sdev->bus) {
- u8 val = of_getintprop_default(sdev->bus->ofdev.node,
- "burst-sizes", 0xff);
- if (val != 0xff)
- bursts &= val;
- }
+ val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff);
+ if (val != 0xff)
+ bursts &= val;
if (bursts == 0xff ||
(bursts & DMA_BURST16) == 0 ||
@@ -194,9 +194,9 @@ static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
esp->bursts = bursts;
}
-static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma)
{
- esp_get_scsi_id(esp);
+ esp_get_scsi_id(esp, espdma);
esp_get_differential(esp);
esp_get_clock_params(esp);
esp_get_bursts(esp, espdma);
@@ -215,25 +215,33 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)
static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
size_t sz, int dir)
{
- return sbus_map_single(esp->dev, buf, sz, dir);
+ struct of_device *op = esp->dev;
+
+ return dma_map_single(&op->dev, buf, sz, dir);
}
static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
int num_sg, int dir)
{
- return sbus_map_sg(esp->dev, sg, num_sg, dir);
+ struct of_device *op = esp->dev;
+
+ return dma_map_sg(&op->dev, sg, num_sg, dir);
}
static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
size_t sz, int dir)
{
- sbus_unmap_single(esp->dev, addr, sz, dir);
+ struct of_device *op = esp->dev;
+
+ dma_unmap_single(&op->dev, addr, sz, dir);
}
static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
int num_sg, int dir)
{
- sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+ struct of_device *op = esp->dev;
+
+ dma_unmap_sg(&op->dev, sg, num_sg, dir);
}
static int sbus_esp_irq_pending(struct esp *esp)
@@ -247,24 +255,26 @@ static void sbus_esp_reset_dma(struct esp *esp)
{
int can_do_burst16, can_do_burst32, can_do_burst64;
int can_do_sbus64, lim;
+ struct of_device *op;
u32 val;
can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
can_do_burst64 = 0;
can_do_sbus64 = 0;
- if (sbus_can_dma_64bit(esp->dev))
+ op = esp->dev;
+ if (sbus_can_dma_64bit())
can_do_sbus64 = 1;
- if (sbus_can_burst64(esp->sdev))
+ if (sbus_can_burst64())
can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
/* Put the DVMA into a known state. */
- if (esp->dma->revision != dvmahme) {
+ if (esp->dmarev != dvmahme) {
val = dma_read32(DMA_CSR);
dma_write32(val | DMA_RST_SCSI, DMA_CSR);
dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
}
- switch (esp->dma->revision) {
+ switch (esp->dmarev) {
case dvmahme:
dma_write32(DMA_RESET_FAS366, DMA_CSR);
dma_write32(DMA_RST_SCSI, DMA_CSR);
@@ -282,7 +292,7 @@ static void sbus_esp_reset_dma(struct esp *esp)
if (can_do_sbus64) {
esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
- sbus_set_sbus64(esp->dev, esp->bursts);
+ sbus_set_sbus64(&op->dev, esp->bursts);
}
lim = 1000;
@@ -346,14 +356,14 @@ static void sbus_esp_dma_drain(struct esp *esp)
u32 csr;
int lim;
- if (esp->dma->revision == dvmahme)
+ if (esp->dmarev == dvmahme)
return;
csr = dma_read32(DMA_CSR);
if (!(csr & DMA_FIFO_ISDRAIN))
return;
- if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+ if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1)
dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
lim = 1000;
@@ -369,7 +379,7 @@ static void sbus_esp_dma_drain(struct esp *esp)
static void sbus_esp_dma_invalidate(struct esp *esp)
{
- if (esp->dma->revision == dvmahme) {
+ if (esp->dmarev == dvmahme) {
dma_write32(DMA_RST_SCSI, DMA_CSR);
esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
@@ -440,7 +450,7 @@ static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
else
csr &= ~DMA_ST_WRITE;
dma_write32(csr, DMA_CSR);
- if (esp->dma->revision == dvmaesc1) {
+ if (esp->dmarev == dvmaesc1) {
u32 end = PAGE_ALIGN(addr + dma_count + 16U);
dma_write32(end - addr, DMA_COUNT);
}
@@ -476,10 +486,8 @@ static const struct esp_driver_ops sbus_esp_ops = {
.dma_error = sbus_esp_dma_error,
};
-static int __devinit esp_sbus_probe_one(struct device *dev,
- struct sbus_dev *esp_dev,
- struct sbus_dev *espdma,
- struct sbus_bus *sbus,
+static int __devinit esp_sbus_probe_one(struct of_device *op,
+ struct of_device *espdma,
int hme)
{
struct scsi_host_template *tpnt = &scsi_esp_template;
@@ -497,13 +505,13 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
esp = shost_priv(host);
esp->host = host;
- esp->dev = esp_dev;
+ esp->dev = op;
esp->ops = &sbus_esp_ops;
if (hme)
esp->flags |= ESP_FLAG_WIDE_CAPABLE;
- err = esp_sbus_find_dma(esp, espdma);
+ err = esp_sbus_setup_dma(esp, espdma);
if (err < 0)
goto fail_unlink;
@@ -525,15 +533,15 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
* come up with the reset bit set, so make sure that
* is clear first.
*/
- if (esp->dma->revision == dvmaesc1) {
+ if (esp->dmarev == dvmaesc1) {
u32 val = dma_read32(DMA_CSR);
dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
}
- dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+ dev_set_drvdata(&op->dev, esp);
- err = scsi_esp_register(esp, dev);
+ err = scsi_esp_register(esp, &op->dev);
if (err)
goto fail_free_irq;
@@ -542,41 +550,46 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
fail_free_irq:
free_irq(host->irq, esp);
fail_unmap_command_block:
- sbus_free_consistent(esp->dev, 16,
- esp->command_block,
- esp->command_block_dma);
+ dma_free_coherent(&op->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
fail_unmap_regs:
- sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+ of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE);
fail_unlink:
scsi_host_put(host);
fail:
return err;
}
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
- struct sbus_dev *dma_sdev = NULL;
+ struct device_node *dma_node = NULL;
+ struct device_node *dp = op->node;
+ struct of_device *dma_of = NULL;
int hme = 0;
if (dp->parent &&
(!strcmp(dp->parent->name, "espdma") ||
!strcmp(dp->parent->name, "dma")))
- dma_sdev = sdev->parent;
+ dma_node = dp->parent;
else if (!strcmp(dp->name, "SUNW,fas")) {
- dma_sdev = sdev;
+ dma_node = op->node;
hme = 1;
}
+ if (dma_node)
+ dma_of = of_find_device_by_node(dma_node);
+ if (!dma_of)
+ return -ENODEV;
- return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
- sdev->bus, hme);
+ return esp_sbus_probe_one(op, dma_of, hme);
}
-static int __devexit esp_sbus_remove(struct of_device *dev)
+static int __devexit esp_sbus_remove(struct of_device *op)
{
- struct esp *esp = dev_get_drvdata(&dev->dev);
+ struct esp *esp = dev_get_drvdata(&op->dev);
+ struct of_device *dma_of = esp->dma;
unsigned int irq = esp->host->irq;
+ bool is_hme;
u32 val;
scsi_esp_unregister(esp);
@@ -586,17 +599,25 @@ static int __devexit esp_sbus_remove(struct of_device *dev)
dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
free_irq(irq, esp);
- sbus_free_consistent(esp->dev, 16,
- esp->command_block,
- esp->command_block_dma);
- sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+ is_hme = (esp->dmarev == dvmahme);
+
+ dma_free_coherent(&op->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
+ of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs,
+ SBUS_ESP_REG_SIZE);
+ of_iounmap(&dma_of->resource[0], esp->dma_regs,
+ resource_size(&dma_of->resource[0]));
scsi_host_put(esp->host);
+ dev_set_drvdata(&op->dev, NULL);
+
return 0;
}
-static struct of_device_id esp_match[] = {
+static const struct of_device_id esp_match[] = {
{
.name = "SUNW,esp",
},
@@ -619,7 +640,7 @@ static struct of_platform_driver esp_sbus_driver = {
static int __init sunesp_init(void)
{
- return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&esp_sbus_driver, &of_bus_type);
}
static void __exit sunesp_exit(void)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 9ccc563d873..d4104a3bbe8 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -44,6 +44,10 @@
#include "8250.h"
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
/*
* Configuration:
* share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
@@ -53,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+ return (serial8250_reg.minor - 64) + port->line;
+}
+
/*
* Debugging.
*/
@@ -536,7 +547,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
/*
* FIFO support.
*/
-static inline void serial8250_clear_fifos(struct uart_8250_port *p)
+static void serial8250_clear_fifos(struct uart_8250_port *p)
{
if (p->capabilities & UART_CAP_FIFO) {
serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -551,7 +562,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p)
* capability" bit enabled. Note that on XR16C850s, we need to
* reset LCR to write to IER.
*/
-static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
{
if (p->capabilities & UART_CAP_SLEEP) {
if (p->capabilities & UART_CAP_EFR) {
@@ -993,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
return;
DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
- up->port.line, up->port.iobase, up->port.membase);
+ serial_index(&up->port), up->port.iobase, up->port.membase);
/*
* We really do need global IRQs disabled here - we're going to
@@ -1128,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
if (up->capabilities != uart_config[up->port.type].flags) {
printk(KERN_WARNING
"ttyS%d: detected caps %08x should be %08x\n",
- up->port.line, up->capabilities,
- uart_config[up->port.type].flags);
+ serial_index(&up->port), up->capabilities,
+ uart_config[up->port.type].flags);
}
up->port.fifosize = uart_config[up->port.type].fifo_size;
@@ -1424,8 +1435,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
/*
* This handles the interrupt from one port.
*/
-static inline void
-serial8250_handle_port(struct uart_8250_port *up)
+static void serial8250_handle_port(struct uart_8250_port *up)
{
unsigned int status;
unsigned long flags;
@@ -1719,7 +1729,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
/*
* Wait for transmitter & holding register to empty
*/
-static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int status, tmout = 10000;
@@ -1854,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port)
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
(serial_inp(up, UART_LSR) == 0xff)) {
- printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+ printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+ serial_index(&up->port));
return -ENODEV;
}
@@ -1909,7 +1920,8 @@ static int serial8250_startup(struct uart_port *port)
*/
if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
up->bugs |= UART_BUG_THRE;
- pr_debug("ttyS%d - using backup timer\n", port->line);
+ pr_debug("ttyS%d - using backup timer\n",
+ serial_index(port));
}
}
@@ -1969,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port)
if (!(up->bugs & UART_BUG_TXEN)) {
up->bugs |= UART_BUG_TXEN;
pr_debug("ttyS%d - enabling bad tx status workarounds\n",
- port->line);
+ serial_index(port));
}
} else {
up->bugs &= ~UART_BUG_TXEN;
@@ -2630,7 +2642,6 @@ static int serial8250_console_early_setup(void)
return serial8250_find_port_for_earlycon();
}
-static struct uart_driver serial8250_reg;
static struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
@@ -2677,7 +2688,6 @@ static struct uart_driver serial8250_reg = {
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
- .nr = UART_NR,
.cons = SERIAL8250_CONSOLE,
};
@@ -2959,10 +2969,12 @@ static int __init serial8250_init(void)
"%d ports, IRQ sharing %sabled\n", nr_uarts,
share_irqs ? "en" : "dis");
- for (i = 0; i < NR_IRQS; i++)
- spin_lock_init(&irq_lists[i].lock);
-
+#ifdef CONFIG_SPARC
+ ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+ serial8250_reg.nr = UART_NR;
ret = uart_register_driver(&serial8250_reg);
+#endif
if (ret)
goto out;
@@ -2987,7 +2999,11 @@ static int __init serial8250_init(void)
put_dev:
platform_device_put(serial8250_isa_devs);
unreg_uart_drv:
+#ifdef CONFIG_SPARC
+ sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
uart_unregister_driver(&serial8250_reg);
+#endif
out:
return ret;
}
@@ -3006,7 +3022,11 @@ static void __exit serial8250_exit(void)
platform_driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
+#ifdef CONFIG_SPARC
+ sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
uart_unregister_driver(&serial8250_reg);
+#endif
}
module_init(serial8250_init);
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index c2f23933155..c014ffb110e 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev)
* The device may have been disabled. Re-enable it.
*/
err = pci_enable_device(dev);
+ /* FIXME: We cannot simply error out here */
if (err)
- return err;
-
+ printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n");
pciserial_resume_ports(priv);
}
return 0;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 77cb34270fc..31786b3b0a6 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -9,7 +9,6 @@ menu "Serial drivers"
# The new 8250/16550 serial drivers
config SERIAL_8250
tristate "8250/16550 and compatible serial support"
- depends on (BROKEN || !SPARC)
select SERIAL_CORE
---help---
This selects whether you want to include the driver for the standard
@@ -994,24 +993,12 @@ config SERIAL_68328_RTS_CTS
bool "Support RTS/CTS on 68328 serial port"
depends on SERIAL_68328
-config SERIAL_COLDFIRE
- bool "ColdFire serial support (DEPRECATED)"
- depends on COLDFIRE
- help
- This driver supports the built-in serial ports of the Motorola ColdFire
- family of CPUs.
- This driver is deprecated because it supports only the old interface
- for serial drivers and features like magic keys are not working.
- Please switch to the new style driver because this driver will be
- removed soon.
-
config SERIAL_MCF
- bool "Coldfire serial support (new style driver)"
+ bool "Coldfire serial support"
depends on COLDFIRE
select SERIAL_CORE
help
- This new serial driver supports the Freescale Coldfire serial ports
- using the new serial driver subsystem.
+ This serial driver supports the Freescale Coldfire serial ports.
config SERIAL_MCF_BAUDRATE
int "Default baudrate for Coldfire serial ports"
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 7e7383e890d..0c17c8ddb19 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -4,6 +4,16 @@
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o
+
+# These Sparc drivers have to appear before others such as 8250
+# which share ttySx minor node space. Otherwise console device
+# names change and other unplesantries.
+obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
+obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
obj-$(CONFIG_SERIAL_8250) += 8250.o
obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
@@ -31,16 +41,10 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
-obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
-obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
-obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
-obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
-obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_68360) += 68360serial.o
-obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 4a0d30bed9f..569f0e2476c 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -1,7 +1,7 @@
/*
* Blackfin On-Chip Serial Driver
*
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2008 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -42,6 +42,9 @@
#define BFIN_SERIAL_MAJOR 204
#define BFIN_SERIAL_MINOR 64
+static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
+static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
+
/*
* Setup for console. Argument comes from the menuconfig
*/
@@ -126,13 +129,13 @@ static int kgdb_entry_state;
void kgdb_put_debug_char(int chr)
{
struct bfin_serial_port *uart;
-
+
if (CONFIG_KGDB_UART_PORT < 0
|| CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
uart = &bfin_serial_ports[0];
else
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
+
while (!(UART_GET_LSR(uart) & THRE)) {
SSYNC();
}
@@ -152,7 +155,7 @@ int kgdb_get_debug_char(void)
uart = &bfin_serial_ports[0];
else
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
+
while(!(UART_GET_LSR(uart) & DR)) {
SSYNC();
}
@@ -298,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
bfin_serial_mctrl_check(uart);
if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
- bfin_serial_stop_tx(&uart->port);
+#ifdef CONFIG_BF54x
+ /* Clear TFI bit */
+ UART_PUT_LSR(uart, TFI);
+#endif
+ UART_CLEAR_IER(uart, ETBEI);
return;
}
@@ -317,9 +324,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port);
-
- if (uart_circ_empty(xmit))
- bfin_serial_stop_tx(&uart->port);
}
static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
@@ -645,6 +649,42 @@ static int bfin_serial_startup(struct uart_port *port)
free_irq(uart->port.irq, uart);
return -EBUSY;
}
+
+# ifdef CONFIG_BF54x
+ {
+ unsigned uart_dma_ch_rx, uart_dma_ch_tx;
+
+ switch (uart->port.irq) {
+ case IRQ_UART3_RX:
+ uart_dma_ch_rx = CH_UART3_RX;
+ uart_dma_ch_tx = CH_UART3_TX;
+ break;
+ case IRQ_UART2_RX:
+ uart_dma_ch_rx = CH_UART2_RX;
+ uart_dma_ch_tx = CH_UART2_TX;
+ break;
+ default:
+ uart_dma_ch_rx = uart_dma_ch_tx = 0;
+ break;
+ };
+
+ if (uart_dma_ch_rx &&
+ request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
+ printk(KERN_NOTICE"Fail to attach UART interrupt\n");
+ free_irq(uart->port.irq, uart);
+ free_irq(uart->port.irq + 1, uart);
+ return -EBUSY;
+ }
+ if (uart_dma_ch_tx &&
+ request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
+ printk(KERN_NOTICE "Fail to attach UART interrupt\n");
+ free_dma(uart_dma_ch_rx);
+ free_irq(uart->port.irq, uart);
+ free_irq(uart->port.irq + 1, uart);
+ return -EBUSY;
+ }
+ }
+# endif
#endif
UART_SET_IER(uart, ERBFI);
return 0;
@@ -662,6 +702,20 @@ static void bfin_serial_shutdown(struct uart_port *port)
del_timer(&(uart->rx_dma_timer));
dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
#else
+#ifdef CONFIG_BF54x
+ switch (uart->port.irq) {
+ case IRQ_UART3_RX:
+ free_dma(CH_UART3_RX);
+ free_dma(CH_UART3_TX);
+ break;
+ case IRQ_UART2_RX:
+ free_dma(CH_UART2_RX);
+ free_dma(CH_UART2_TX);
+ break;
+ default:
+ break;
+ };
+#endif
#ifdef CONFIG_KGDB_UART
if (uart->port.line != CONFIG_KGDB_UART_PORT)
#endif
@@ -757,6 +811,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
val |= UCEN;
UART_PUT_GCTL(uart, val);
+ /* Port speed changed, update the per-port timeout. */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
spin_unlock_irqrestore(&uart->port.lock, flags);
}
@@ -859,8 +916,9 @@ static void __init bfin_serial_init_ports(void)
return;
first = 0;
- for (i = 0; i < nr_ports; i++) {
+ for (i = 0; i < nr_active_ports; i++) {
bfin_serial_ports[i].port.uartclk = get_sclk();
+ bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE;
bfin_serial_ports[i].port.ops = &bfin_serial_pops;
bfin_serial_ports[i].port.line = i;
bfin_serial_ports[i].port.iotype = UPIO_MEM;
@@ -961,7 +1019,7 @@ bfin_serial_console_setup(struct console *co, char *options)
* if so, search for the first available port that does have
* console support.
*/
- if (co->index == -1 || co->index >= nr_ports)
+ if (co->index == -1 || co->index >= nr_active_ports)
co->index = 0;
uart = &bfin_serial_ports[co->index];
@@ -1056,7 +1114,7 @@ static __init void early_serial_write(struct console *con, const char *s,
}
}
-static struct __init console bfin_early_serial_console = {
+static struct __initdata console bfin_early_serial_console = {
.name = "early_BFuart",
.write = early_serial_write,
.device = uart_console_device,
@@ -1072,7 +1130,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
struct bfin_serial_port *uart;
struct ktermios t;
- if (port == -1 || port >= nr_ports)
+ if (port == -1 || port >= nr_active_ports)
port = 0;
bfin_serial_init_ports();
bfin_early_serial_console.index = port;
@@ -1100,20 +1158,26 @@ static struct uart_driver bfin_serial_reg = {
static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
{
- struct bfin_serial_port *uart = platform_get_drvdata(dev);
+ int i;
- if (uart)
- uart_suspend_port(&bfin_serial_reg, &uart->port);
+ for (i = 0; i < nr_active_ports; i++) {
+ if (bfin_serial_ports[i].port.dev != &dev->dev)
+ continue;
+ uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+ }
return 0;
}
static int bfin_serial_resume(struct platform_device *dev)
{
- struct bfin_serial_port *uart = platform_get_drvdata(dev);
+ int i;
- if (uart)
- uart_resume_port(&bfin_serial_reg, &uart->port);
+ for (i = 0; i < nr_active_ports; i++) {
+ if (bfin_serial_ports[i].port.dev != &dev->dev)
+ continue;
+ uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+ }
return 0;
}
@@ -1128,32 +1192,31 @@ static int bfin_serial_probe(struct platform_device *dev)
break;
if (i < dev->num_resources) {
- for (i = 0; i < nr_ports; i++, res++) {
+ for (i = 0; i < nr_active_ports; i++, res++) {
if (bfin_serial_ports[i].port.mapbase != res->start)
continue;
bfin_serial_ports[i].port.dev = &dev->dev;
uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
- platform_set_drvdata(dev, &bfin_serial_ports[i]);
}
}
return 0;
}
-static int bfin_serial_remove(struct platform_device *pdev)
+static int bfin_serial_remove(struct platform_device *dev)
{
- struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
+ int i;
+ for (i = 0; i < nr_active_ports; i++) {
+ if (bfin_serial_ports[i].port.dev != &dev->dev)
+ continue;
+ uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+ bfin_serial_ports[i].port.dev = NULL;
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
- gpio_free(uart->cts_pin);
- gpio_free(uart->rts_pin);
+ gpio_free(bfin_serial_ports[i].cts_pin);
+ gpio_free(bfin_serial_ports[i].rts_pin);
#endif
-
- platform_set_drvdata(pdev, NULL);
-
- if (uart)
- uart_remove_one_port(&bfin_serial_reg, &uart->port);
+ }
return 0;
}
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index bf94a770bb4..211c21797ce 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = {
#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
static struct ktermios *serial_termios[NR_PORTS];
-static struct ktermios *serial_termios_locked[NR_PORTS];
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
static struct fast_timer fast_timers[NR_PORTS];
#endif
@@ -4419,6 +4418,7 @@ rs_init(void)
rs485_pa_bit)) {
printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
"RS485 pin\n");
+ put_tty_driver(driver);
return -EBUSY;
}
#endif
@@ -4427,6 +4427,7 @@ rs_init(void)
rs485_port_g_bit)) {
printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
"RS485 pin\n");
+ put_tty_driver(driver);
return -EBUSY;
}
#endif
@@ -4446,8 +4447,6 @@ rs_init(void)
driver->init_termios.c_ispeed = 115200;
driver->init_termios.c_ospeed = 115200;
driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- driver->termios = serial_termios;
- driver->termios_locked = serial_termios_locked;
tty_set_operations(driver, &rs_ops);
serial_driver = driver;
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
deleted file mode 100644
index fbe3835f6b7..00000000000
--- a/drivers/serial/mcfserial.c
+++ /dev/null
@@ -1,1965 +0,0 @@
-#warning This driver is deprecated. Check Kconfig for details.
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (C) 1999-2003 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com>
- * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com>
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- *
- * Changes:
- * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it>
- * some cleanups in mcfrs_write.
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/delay.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/nettel.h>
-#include <asm/uaccess.h>
-#include "mcfserial.h"
-
-struct timer_list mcfrs_timer_struct;
-
-/*
- * Default console baud rate, we use this as the default
- * for all ports so init can just open /dev/console and
- * keep going. Perhaps one day the cflag settings for the
- * console can be used instead.
- */
-#if defined(CONFIG_HW_FEITH)
-#define CONSOLE_BAUD_RATE 38400
-#define DEFAULT_CBAUD B38400
-#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \
- defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO)
-#define CONSOLE_BAUD_RATE 115200
-#define DEFAULT_CBAUD B115200
-#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
- defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
-#define CONSOLE_BAUD_RATE 19200
-#define DEFAULT_CBAUD B19200
-#endif
-
-#ifndef CONSOLE_BAUD_RATE
-#define CONSOLE_BAUD_RATE 9600
-#define DEFAULT_CBAUD B9600
-#endif
-
-int mcfrs_console_inited = 0;
-int mcfrs_console_port = -1;
-int mcfrs_console_baud = CONSOLE_BAUD_RATE;
-int mcfrs_console_cbaud = DEFAULT_CBAUD;
-
-/*
- * Driver data structures.
- */
-static struct tty_driver *mcfrs_serial_driver;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Debugging...
- */
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x)
-#define IRQBASE (MCFINT_VECBASE+MCFINT_UART0)
-#else
-#define IRQBASE 73
-#endif
-
-/*
- * Configuration table, UARTs to look for at startup.
- */
-static struct mcf_serial mcfrs_table[] = {
- { /* ttyS0 */
- .magic = 0,
- .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1),
- .irq = IRQBASE,
- .flags = ASYNC_BOOT_AUTOCONF,
- },
-#ifdef MCFUART_BASE2
- { /* ttyS1 */
- .magic = 0,
- .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2),
- .irq = IRQBASE+1,
- .flags = ASYNC_BOOT_AUTOCONF,
- },
-#endif
-#ifdef MCFUART_BASE3
- { /* ttyS2 */
- .magic = 0,
- .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3),
- .irq = IRQBASE+2,
- .flags = ASYNC_BOOT_AUTOCONF,
- },
-#endif
-#ifdef MCFUART_BASE4
- { /* ttyS3 */
- .magic = 0,
- .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4),
- .irq = IRQBASE+3,
- .flags = ASYNC_BOOT_AUTOCONF,
- },
-#endif
-};
-
-
-#define NR_PORTS (sizeof(mcfrs_table) / sizeof(struct mcf_serial))
-
-/*
- * This is used to figure out the divisor speeds and the timeouts.
- */
-static int mcfrs_baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
-};
-#define MCFRS_BAUD_TABLE_SIZE \
- (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0]))
-
-
-#ifdef CONFIG_MAGIC_SYSRQ
-/*
- * Magic system request keys. Used for debugging...
- */
-extern int magic_sysrq_key(int ch);
-#endif
-
-
-/*
- * Forware declarations...
- */
-static void mcfrs_change_speed(struct mcf_serial *info);
-static void mcfrs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-
-static inline int serial_paranoia_check(struct mcf_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char badmagic[] =
- "MCFRS(warning): bad magic number for serial struct %s in %s\n";
- static const char badinfo[] =
- "MCFRS(warning): null mcf_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * Sets or clears DTR and RTS on the requested line.
- */
-static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts)
-{
- volatile unsigned char *uartp;
- unsigned long flags;
-
-#if 0
- printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n",
- __FILE__, __LINE__, info, dtr, rts);
-#endif
-
- local_irq_save(flags);
- if (dtr >= 0) {
-#ifdef MCFPP_DTR0
- if (info->line)
- mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1));
- else
- mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0));
-#endif
- }
- if (rts >= 0) {
- uartp = info->addr;
- if (rts) {
- info->sigs |= TIOCM_RTS;
- uartp[MCFUART_UOP1] = MCFUART_UOP_RTS;
- } else {
- info->sigs &= ~TIOCM_RTS;
- uartp[MCFUART_UOP0] = MCFUART_UOP_RTS;
- }
- }
- local_irq_restore(flags);
- return;
-}
-
-/*
- * Gets values of serial signals.
- */
-static int mcfrs_getsignals(struct mcf_serial *info)
-{
- volatile unsigned char *uartp;
- unsigned long flags;
- int sigs;
-#if defined(CONFIG_NETtel) && defined(CONFIG_M5307)
- unsigned short ppdata;
-#endif
-
-#if 0
- printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__);
-#endif
-
- local_irq_save(flags);
- uartp = info->addr;
- sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS;
- sigs |= (info->sigs & TIOCM_RTS);
-
-#ifdef MCFPP_DCD0
-{
- unsigned int ppdata;
- ppdata = mcf_getppdata();
- if (info->line == 0) {
- sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD;
- sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR;
- } else if (info->line == 1) {
- sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD;
- sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR;
- }
-}
-#endif
-
- local_irq_restore(flags);
- return(sigs);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_stop() and mcfrs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void mcfrs_stop(struct tty_struct *tty)
-{
- volatile unsigned char *uartp;
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_stop"))
- return;
-
- local_irq_save(flags);
- uartp = info->addr;
- info->imr &= ~MCFUART_UIR_TXREADY;
- uartp[MCFUART_UIMR] = info->imr;
- local_irq_restore(flags);
-}
-
-static void mcfrs_start(struct tty_struct *tty)
-{
- volatile unsigned char *uartp;
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_start"))
- return;
-
- local_irq_save(flags);
- if (info->xmit_cnt && info->xmit_buf) {
- uartp = info->addr;
- info->imr |= MCFUART_UIR_TXREADY;
- uartp[MCFUART_UIMR] = info->imr;
- }
- local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * mcfrs_interrupt(). They were separated out for readability's sake.
- *
- * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off. People who may want to modify
- * mcfrs_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:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static inline void receive_chars(struct mcf_serial *info)
-{
- volatile unsigned char *uartp;
- struct tty_struct *tty = info->port.tty;
- unsigned char status, ch, flag;
-
- if (!tty)
- return;
-
- uartp = info->addr;
-
- while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
- ch = uartp[MCFUART_URB];
- info->stats.rx++;
-
-#ifdef CONFIG_MAGIC_SYSRQ
- if (mcfrs_console_inited && (info->line == mcfrs_console_port)) {
- if (magic_sysrq_key(ch))
- continue;
- }
-#endif
-
- flag = TTY_NORMAL;
- if (status & MCFUART_USR_RXERR) {
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
- if (status & MCFUART_USR_RXBREAK) {
- info->stats.rxbreak++;
- flag = TTY_BREAK;
- } else if (status & MCFUART_USR_RXPARITY) {
- info->stats.rxparity++;
- flag = TTY_PARITY;
- } else if (status & MCFUART_USR_RXOVERRUN) {
- info->stats.rxoverrun++;
- flag = TTY_OVERRUN;
- } else if (status & MCFUART_USR_RXFRAMING) {
- info->stats.rxframing++;
- flag = TTY_FRAME;
- }
- }
- tty_insert_flip_char(tty, ch, flag);
- }
- tty_schedule_flip(tty);
- return;
-}
-
-static inline void transmit_chars(struct mcf_serial *info)
-{
- volatile unsigned char *uartp;
-
- uartp = info->addr;
-
- if (info->x_char) {
- /* Send special char - probably flow control */
- uartp[MCFUART_UTB] = info->x_char;
- info->x_char = 0;
- info->stats.tx++;
- }
-
- if ((info->xmit_cnt <= 0) || info->port.tty->stopped) {
- info->imr &= ~MCFUART_UIR_TXREADY;
- uartp[MCFUART_UIMR] = info->imr;
- return;
- }
-
- while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) {
- uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++];
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->stats.tx++;
- if (--info->xmit_cnt <= 0)
- break;
- }
-
- if (info->xmit_cnt < WAKEUP_CHARS)
- schedule_work(&info->tqueue);
- return;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
-{
- struct mcf_serial *info;
- unsigned char isr;
-
- info = &mcfrs_table[(irq - IRQBASE)];
- isr = info->addr[MCFUART_UISR] & info->imr;
-
- if (isr & MCFUART_UIR_RXREADY)
- receive_chars(info);
- if (isr & MCFUART_UIR_TXREADY)
- transmit_chars(info);
- return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-static void mcfrs_offintr(struct work_struct *work)
-{
- struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue);
- struct tty_struct *tty = info->port.tty;
-
- if (tty)
- tty_wakeup(tty);
-}
-
-
-/*
- * Change of state on a DCD line.
- */
-void mcfrs_modem_change(struct mcf_serial *info, int dcd)
-{
- if (info->count == 0)
- return;
-
- if (info->flags & ASYNC_CHECK_CD) {
- if (dcd)
- wake_up_interruptible(&info->open_wait);
- else
- schedule_work(&info->tqueue_hangup);
- }
-}
-
-
-#ifdef MCFPP_DCD0
-
-unsigned short mcfrs_ppstatus;
-
-/*
- * This subroutine is called when the RS_TIMER goes off. It is used
- * to monitor the state of the DCD lines - since they have no edge
- * sensors and interrupt generators.
- */
-static void mcfrs_timer(void)
-{
- unsigned int ppstatus, dcdval, i;
-
- ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-
- if (ppstatus != mcfrs_ppstatus) {
- for (i = 0; (i < 2); i++) {
- dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0);
- if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) {
- mcfrs_modem_change(&mcfrs_table[i],
- ((ppstatus & dcdval) ? 0 : 1));
- }
- }
- }
- mcfrs_ppstatus = ppstatus;
-
- /* Re-arm timer */
- mcfrs_timer_struct.expires = jiffies + HZ/25;
- add_timer(&mcfrs_timer_struct);
-}
-
-#endif /* MCFPP_DCD0 */
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- * serial interrupt routine -> (scheduler tqueue) ->
- * do_serial_hangup() -> tty->hangup() -> mcfrs_hangup()
- *
- */
-static void do_serial_hangup(struct work_struct *work)
-{
- struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup);
- struct tty_struct *tty = info->port.tty;
-
- if (tty)
- tty_hangup(tty);
-}
-
-static int startup(struct mcf_serial * info)
-{
- volatile unsigned char *uartp;
- unsigned long flags;
-
- if (info->flags & ASYNC_INITIALIZED)
- return 0;
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- local_irq_save(flags);
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
-
- /*
- * Reset UART, get it into known state...
- */
- uartp = info->addr;
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
- mcfrs_setsignals(info, 1, 1);
-
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- /*
- * and set the speed of the serial port
- */
- mcfrs_change_speed(info);
-
- /*
- * Lastly enable the UART transmitter and receiver, and
- * interrupt enables.
- */
- info->imr = MCFUART_UIR_RXREADY;
- uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
- uartp[MCFUART_UIMR] = info->imr;
-
- info->flags |= ASYNC_INITIALIZED;
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * 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 shutdown(struct mcf_serial * info)
-{
- volatile unsigned char *uartp;
- unsigned long flags;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d (irq %d)....\n", info->line,
- info->irq);
-#endif
-
- local_irq_save(flags);
-
- uartp = info->addr;
- uartp[MCFUART_UIMR] = 0; /* mask all interrupts */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
-
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
- mcfrs_setsignals(info, 0, 0);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- info->flags &= ~ASYNC_INITIALIZED;
- local_irq_restore(flags);
-}
-
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void mcfrs_change_speed(struct mcf_serial *info)
-{
- volatile unsigned char *uartp;
- unsigned int baudclk, cflag;
- unsigned long flags;
- unsigned char mr1, mr2;
- int i;
-#ifdef CONFIG_M5272
- unsigned int fraction;
-#endif
-
- if (!info->port.tty || !info->port.tty->termios)
- return;
- cflag = info->port.tty->termios->c_cflag;
- if (info->addr == 0)
- return;
-
-#if 0
- printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__);
-#endif
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 4)
- info->port.tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (i == 0) {
- mcfrs_setsignals(info, 0, -1);
- return;
- }
-
- /* compute the baudrate clock */
-#ifdef CONFIG_M5272
- /*
- * For the MCF5272, also compute the baudrate fraction.
- */
- baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32;
- fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]);
- fraction *= 16;
- fraction /= (32 * mcfrs_baud_table[i]);
-#else
- baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32;
-#endif
-
- info->baud = mcfrs_baud_table[i];
-
- mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
- mr2 = 0;
-
- switch (cflag & CSIZE) {
- case CS5: mr1 |= MCFUART_MR1_CS5; break;
- case CS6: mr1 |= MCFUART_MR1_CS6; break;
- case CS7: mr1 |= MCFUART_MR1_CS7; break;
- case CS8:
- default: mr1 |= MCFUART_MR1_CS8; break;
- }
-
- if (cflag & PARENB) {
- if (cflag & CMSPAR) {
- if (cflag & PARODD)
- mr1 |= MCFUART_MR1_PARITYMARK;
- else
- mr1 |= MCFUART_MR1_PARITYSPACE;
- } else {
- if (cflag & PARODD)
- mr1 |= MCFUART_MR1_PARITYODD;
- else
- mr1 |= MCFUART_MR1_PARITYEVEN;
- }
- } else {
- mr1 |= MCFUART_MR1_PARITYNONE;
- }
-
- if (cflag & CSTOPB)
- mr2 |= MCFUART_MR2_STOP2;
- else
- mr2 |= MCFUART_MR2_STOP1;
-
- if (cflag & CRTSCTS) {
- mr1 |= MCFUART_MR1_RXRTS;
- mr2 |= MCFUART_MR2_TXCTS;
- }
-
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else
- info->flags |= ASYNC_CHECK_CD;
-
- uartp = info->addr;
-
- local_irq_save(flags);
-#if 0
- printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__,
- mr1, mr2, baudclk);
-#endif
- /*
- Note: pg 12-16 of MCF5206e User's Manual states that a
- software reset should be performed prior to changing
- UMR1,2, UCSR, UACR, bit 7
- */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */
- uartp[MCFUART_UMR] = mr1;
- uartp[MCFUART_UMR] = mr2;
- uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */
- uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */
-#ifdef CONFIG_M5272
- uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */
-#endif
- uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
- uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
- mcfrs_setsignals(info, 1, -1);
- local_irq_restore(flags);
- return;
-}
-
-static void mcfrs_flush_chars(struct tty_struct *tty)
-{
- volatile unsigned char *uartp;
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars"))
- return;
-
- uartp = (volatile unsigned char *) info->addr;
-
- /*
- * re-enable receiver interrupt
- */
- local_irq_save(flags);
- if ((!(info->imr & MCFUART_UIR_RXREADY)) &&
- (info->flags & ASYNC_INITIALIZED) ) {
- info->imr |= MCFUART_UIR_RXREADY;
- uartp[MCFUART_UIMR] = info->imr;
- }
- local_irq_restore(flags);
-
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf)
- return;
-
- /* Enable transmitter */
- local_irq_save(flags);
- info->imr |= MCFUART_UIR_TXREADY;
- uartp[MCFUART_UIMR] = info->imr;
- local_irq_restore(flags);
-}
-
-static int mcfrs_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- volatile unsigned char *uartp;
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
- unsigned long flags;
- int c, total = 0;
-
-#if 0
- printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n",
- __FILE__, __LINE__, (int)tty, (int)buf, count);
-#endif
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf)
- return 0;
-
- local_save_flags(flags);
- while (1) {
- local_irq_disable();
- c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
- ((int)SERIAL_XMIT_SIZE) - info->xmit_head));
- local_irq_restore(flags);
-
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
-
- local_irq_disable();
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- local_irq_restore(flags);
-
- buf += c;
- count -= c;
- total += c;
- }
-
- local_irq_disable();
- uartp = info->addr;
- info->imr |= MCFUART_UIR_TXREADY;
- uartp[MCFUART_UIMR] = info->imr;
- local_irq_restore(flags);
-
- return total;
-}
-
-static int mcfrs_write_room(struct tty_struct *tty)
-{
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int mcfrs_chars_in_buffer(struct tty_struct *tty)
-{
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void mcfrs_flush_buffer(struct tty_struct *tty)
-{
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer"))
- return;
-
- local_irq_save(flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- local_irq_restore(flags);
-
- tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void mcfrs_throttle(struct tty_struct * tty)
-{
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_throttle"))
- return;
-
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
-
- /* Turn off RTS line (do this atomic) */
-}
-
-static void mcfrs_unthrottle(struct tty_struct * tty)
-{
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
-
- /* Assert RTS line (do this atomic) */
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mcf_serial * info,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = (unsigned int) info->addr;
- tmp.irq = info->irq;
- tmp.flags = info->flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct mcf_serial * info,
- struct serial_struct * new_info)
-{
- struct serial_struct new_serial;
- struct mcf_serial old_info;
- int retval = 0;
-
- if (!new_info)
- return -EFAULT;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
- (info->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (info->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- retval = startup(info);
- return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * 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.
- */
-static int get_lsr_info(struct mcf_serial * info, unsigned int *value)
-{
- volatile unsigned char *uartp;
- unsigned long flags;
- unsigned char status;
-
- local_irq_save(flags);
- uartp = info->addr;
- status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;
- local_irq_restore(flags);
-
- return put_user(status,value);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break( struct mcf_serial * info, int duration)
-{
- volatile unsigned char *uartp;
- unsigned long flags;
-
- if (!info->addr)
- return;
- set_current_state(TASK_INTERRUPTIBLE);
- uartp = info->addr;
-
- local_irq_save(flags);
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
- schedule_timeout(duration);
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP;
- local_irq_restore(flags);
-}
-
-static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
- return -ENODEV;
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- return mcfrs_getsignals(info);
-}
-
-static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
- int rts = -1, dtr = -1;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
- return -ENODEV;
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- if (set & TIOCM_RTS)
- rts = 1;
- if (set & TIOCM_DTR)
- dtr = 1;
- if (clear & TIOCM_RTS)
- rts = 0;
- if (clear & TIOCM_DTR)
- dtr = 0;
-
- mcfrs_setsignals(info, dtr, rts);
-
- return 0;
-}
-
-static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
- int retval, error;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- send_break(info, HZ/4); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
- return 0;
- case TIOCGSERIAL:
- if (access_ok(VERIFY_WRITE, (void *) arg,
- sizeof(struct serial_struct)))
- return get_serial_info(info,
- (struct serial_struct *) arg);
- return -EFAULT;
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- if (access_ok(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int)))
- return get_lsr_info(info, (unsigned int *) arg);
- return -EFAULT;
- case TIOCSERGSTRUCT:
- error = copy_to_user((struct mcf_serial *) arg,
- info, sizeof(struct mcf_serial));
- if (error)
- return -EFAULT;
- return 0;
-
-#ifdef TIOCSET422
- case TIOCSET422: {
- unsigned int val;
- get_user(val, (unsigned int *) arg);
- mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11));
- break;
- }
- case TIOCGET422: {
- unsigned int val;
- val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1;
- put_user(val, (unsigned int *) arg);
- break;
- }
-#endif
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
-
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
-
- mcfrs_change_speed(info);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- mcfrs_setsignals(info, -1, 1);
-#if 0
- mcfrs_start(tty);
-#endif
- }
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_close()
- *
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * S structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void mcfrs_close(struct tty_struct *tty, struct file * filp)
-{
- volatile unsigned char *uartp;
- struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
- unsigned long flags;
-
- if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close"))
- return;
-
- local_irq_save(flags);
-
- if (tty_hung_up_p(filp)) {
- local_irq_restore(flags);
- return;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("MCFRS: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
- if (--info->count < 0) {
- printk("MCFRS: bad serial port count for ttyS%d: %d\n",
- info->line, info->count);
- info->count = 0;
- }
- if (info->count) {
- local_irq_restore(flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
-
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
-
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- info->imr &= ~MCFUART_UIR_RXREADY;
- uartp = info->addr;
- uartp[MCFUART_UIMR] = info->imr;
-
-#if 0
- /* FIXME: do we need to keep this enabled for console?? */
- if (mcfrs_console_inited && (mcfrs_console_port == info->line)) {
- /* Do not disable the UART */ ;
- } else
-#endif
- shutdown(info);
- mcfrs_flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- tty->closing = 0;
- info->event = 0;
- info->port.tty = NULL;
-#if 0
- if (tty->ldisc.num != ldiscs[N_TTY].num) {
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
- if (tty->ldisc.open)
- (tty->ldisc.open)(tty);
- }
-#endif
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
- local_irq_restore(flags);
-}
-
-/*
- * mcfrs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void
-mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-#ifdef CONFIG_M5272
-#define MCF5272_FIFO_SIZE 25 /* fifo size + shift reg */
-
- struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
- volatile unsigned char *uartp;
- unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent"))
- return;
-
- orig_jiffies = jiffies;
-
- /*
- * Set the check interval to be 1/5 of the approximate time
- * to send the entire fifo, and make it at least 1. The check
- * interval should also be less than the timeout.
- *
- * Note: we have to use pretty tight timings here to satisfy
- * the NIST-PCTS.
- */
- lock_kernel();
-
- fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
- char_time = fifo_time / 5;
- if (char_time == 0)
- char_time = 1;
- if (timeout && timeout < char_time)
- char_time = timeout;
-
- /*
- * Clamp the timeout period at 2 * the time to empty the
- * fifo. Just to be safe, set the minimum at .5 seconds.
- */
- fifo_time *= 2;
- if (fifo_time < (HZ/2))
- fifo_time = HZ/2;
- if (!timeout || timeout > fifo_time)
- timeout = fifo_time;
-
- /*
- * Account for the number of bytes in the UART
- * transmitter FIFO plus any byte being shifted out.
- */
- uartp = (volatile unsigned char *) info->addr;
- for (;;) {
- fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB);
- if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY|
- MCFUART_USR_TXEMPTY)) ==
- MCFUART_USR_TXREADY)
- fifo_cnt++;
- if (fifo_cnt == 0)
- break;
- msleep_interruptible(jiffies_to_msecs(char_time));
- if (signal_pending(current))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
- }
- unlock_kernel();
-#else
- /*
- * For the other coldfire models, assume all data has been sent
- */
-#endif
-}
-
-/*
- * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-void mcfrs_hangup(struct tty_struct *tty)
-{
- struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "mcfrs_hangup"))
- return;
-
- mcfrs_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- info->port.tty = NULL;
- wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * mcfrs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct mcf_serial *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * mcfrs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- info->count--;
- info->blocked_open++;
- while (1) {
- local_irq_disable();
- mcfrs_setsignals(info, 1, 1);
- local_irq_enable();
- current->state = TASK_INTERRUPTIBLE;
- if (tty_hung_up_p(filp) ||
- !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ASYNC_CLOSING) &&
- (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-int mcfrs_open(struct tty_struct *tty, struct file * filp)
-{
- struct mcf_serial *info;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (line >= NR_PORTS))
- return -ENODEV;
- info = mcfrs_table + line;
- if (serial_paranoia_check(info, tty->name, "mcfrs_open"))
- return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
- printk("mcfrs_open %s, count = %d\n", tty->name, info->count);
-#endif
- info->count++;
- tty->driver_data = info;
- info->port.tty = tty;
-
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval)
- return retval;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("mcfrs_open returning after block_til_ready with %d\n",
- retval);
-#endif
- return retval;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("mcfrs_open %s successful...\n", tty->name);
-#endif
- return 0;
-}
-
-/*
- * Based on the line number set up the internal interrupt stuff.
- */
-static void mcfrs_irqinit(struct mcf_serial *info)
-{
-#if defined(CONFIG_M5272)
- volatile unsigned long *icrp;
- volatile unsigned long *portp;
- volatile unsigned char *uartp;
-
- uartp = info->addr;
- icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
-
- switch (info->line) {
- case 0:
- *icrp = 0xe0000000;
- break;
- case 1:
- *icrp = 0x0e000000;
- break;
- default:
- printk("MCFRS: don't know how to handle UART %d interrupt?\n",
- info->line);
- return;
- }
-
- /* Enable the output lines for the serial ports */
- portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT);
- *portp = (*portp & ~0x000000ff) | 0x00000055;
- portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
- *portp = (*portp & ~0x000003fc) | 0x000002a8;
-#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
- volatile unsigned char *icrp, *uartp;
- volatile unsigned long *imrp;
-
- uartp = info->addr;
-
- icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
- MCFINTC_ICR0 + MCFINT_UART0 + info->line);
- *icrp = 0x30 + info->line; /* level 6, line based priority */
-
- imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
- MCFINTC_IMRL);
- *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
-#if defined(CONFIG_M527x)
- {
- /*
- * External Pin Mask Setting & Enable External Pin for Interface
- * mrcbis@aliceposta.it
- */
- u16 *serpin_enable_mask;
- serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART);
- if (info->line == 0)
- *serpin_enable_mask |= UART0_ENABLE_MASK;
- else if (info->line == 1)
- *serpin_enable_mask |= UART1_ENABLE_MASK;
- else if (info->line == 2)
- *serpin_enable_mask |= UART2_ENABLE_MASK;
- }
-#endif
-#if defined(CONFIG_M528x)
- /* make sure PUAPAR is set for UART0 and UART1 */
- if (info->line < 2) {
- volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR);
- *portp |= (0x03 << (info->line * 2));
- }
-#endif
-#elif defined(CONFIG_M520x)
- volatile unsigned char *icrp, *uartp;
- volatile unsigned long *imrp;
-
- uartp = info->addr;
-
- icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
- MCFINTC_ICR0 + MCFINT_UART0 + info->line);
- *icrp = 0x03;
-
- imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
- MCFINTC_IMRL);
- *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
- if (info->line < 2) {
- unsigned short *uart_par;
- uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART);
- if (info->line == 0)
- *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0
- | MCF_GPIO_PAR_UART_PAR_URXD0;
- else if (info->line == 1)
- *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1
- | MCF_GPIO_PAR_UART_PAR_URXD1;
- } else if (info->line == 2) {
- unsigned char *feci2c_par;
- feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
- *feci2c_par &= ~0x0F;
- *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
- | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
- }
-#elif defined(CONFIG_M532x)
- volatile unsigned char *uartp;
- uartp = info->addr;
- switch (info->line) {
- case 0:
- MCF_INTC0_ICR26 = 0x3;
- MCF_INTC0_CIMR = 26;
- /* GPIO initialization */
- MCF_GPIO_PAR_UART |= 0x000F;
- break;
- case 1:
- MCF_INTC0_ICR27 = 0x3;
- MCF_INTC0_CIMR = 27;
- /* GPIO initialization */
- MCF_GPIO_PAR_UART |= 0x0FF0;
- break;
- case 2:
- MCF_INTC0_ICR28 = 0x3;
- MCF_INTC0_CIMR = 28;
- /* GPIOs also must be initalized, depends on board */
- break;
- }
-#else
- volatile unsigned char *icrp, *uartp;
-
- switch (info->line) {
- case 0:
- icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR);
- *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
- MCFSIM_ICR_PRI1;
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
- break;
- case 1:
- icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR);
- *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
- MCFSIM_ICR_PRI2;
- mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
- break;
- default:
- printk("MCFRS: don't know how to handle UART %d interrupt?\n",
- info->line);
- return;
- }
-
- uartp = info->addr;
- uartp[MCFUART_UIVR] = info->irq;
-#endif
-
- /* Clear mask, so no surprise interrupts. */
- uartp[MCFUART_UIMR] = 0;
-
- if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED,
- "ColdFire UART", NULL)) {
- printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
- "vector=%d\n", info->line, info->irq);
- }
-
- return;
-}
-
-
-char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";
-
-
-/*
- * Serial stats reporting...
- */
-int mcfrs_readproc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- struct mcf_serial *info;
- char str[20];
- int len, sigs, i;
-
- len = sprintf(page, mcfrs_drivername);
- for (i = 0; (i < NR_PORTS); i++) {
- info = &mcfrs_table[i];
- len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",
- i, (unsigned int) info->addr, info->irq, info->baud);
- if (info->stats.rx || info->stats.tx)
- len += sprintf((page + len), "tx:%d rx:%d ",
- info->stats.tx, info->stats.rx);
- if (info->stats.rxframing)
- len += sprintf((page + len), "fe:%d ",
- info->stats.rxframing);
- if (info->stats.rxparity)
- len += sprintf((page + len), "pe:%d ",
- info->stats.rxparity);
- if (info->stats.rxbreak)
- len += sprintf((page + len), "brk:%d ",
- info->stats.rxbreak);
- if (info->stats.rxoverrun)
- len += sprintf((page + len), "oe:%d ",
- info->stats.rxoverrun);
-
- str[0] = str[1] = 0;
- if ((sigs = mcfrs_getsignals(info))) {
- if (sigs & TIOCM_RTS)
- strcat(str, "|RTS");
- if (sigs & TIOCM_CTS)
- strcat(str, "|CTS");
- if (sigs & TIOCM_DTR)
- strcat(str, "|DTR");
- if (sigs & TIOCM_CD)
- strcat(str, "|CD");
- }
-
- len += sprintf((page + len), "%s\n", &str[1]);
- }
-
- return(len);
-}
-
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
- printk(mcfrs_drivername);
-}
-
-static const struct tty_operations mcfrs_ops = {
- .open = mcfrs_open,
- .close = mcfrs_close,
- .write = mcfrs_write,
- .flush_chars = mcfrs_flush_chars,
- .write_room = mcfrs_write_room,
- .chars_in_buffer = mcfrs_chars_in_buffer,
- .flush_buffer = mcfrs_flush_buffer,
- .ioctl = mcfrs_ioctl,
- .throttle = mcfrs_throttle,
- .unthrottle = mcfrs_unthrottle,
- .set_termios = mcfrs_set_termios,
- .stop = mcfrs_stop,
- .start = mcfrs_start,
- .hangup = mcfrs_hangup,
- .read_proc = mcfrs_readproc,
- .wait_until_sent = mcfrs_wait_until_sent,
- .tiocmget = mcfrs_tiocmget,
- .tiocmset = mcfrs_tiocmset,
-};
-
-/* mcfrs_init inits the driver */
-static int __init
-mcfrs_init(void)
-{
- struct mcf_serial *info;
- unsigned long flags;
- int i;
-
- /* Setup base handler, and timer table. */
-#ifdef MCFPP_DCD0
- init_timer(&mcfrs_timer_struct);
- mcfrs_timer_struct.function = mcfrs_timer;
- mcfrs_timer_struct.data = 0;
- mcfrs_timer_struct.expires = jiffies + HZ/25;
- add_timer(&mcfrs_timer_struct);
- mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
-#endif
- mcfrs_serial_driver = alloc_tty_driver(NR_PORTS);
- if (!mcfrs_serial_driver)
- return -ENOMEM;
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- mcfrs_serial_driver->owner = THIS_MODULE;
- mcfrs_serial_driver->name = "ttyS";
- mcfrs_serial_driver->driver_name = "mcfserial";
- mcfrs_serial_driver->major = TTY_MAJOR;
- mcfrs_serial_driver->minor_start = 64;
- mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL;
- mcfrs_serial_driver->init_termios = tty_std_termios;
-
- mcfrs_serial_driver->init_termios.c_cflag =
- mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
- mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW;
-
- tty_set_operations(mcfrs_serial_driver, &mcfrs_ops);
-
- if (tty_register_driver(mcfrs_serial_driver)) {
- printk("MCFRS: Couldn't register serial driver\n");
- put_tty_driver(mcfrs_serial_driver);
- return(-EBUSY);
- }
-
- local_irq_save(flags);
-
- /*
- * Configure all the attached serial ports.
- */
- for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {
- info->magic = SERIAL_MAGIC;
- info->line = i;
- info->port.tty = NULL;
- info->custom_divisor = 16;
- info->close_delay = 50;
- info->closing_wait = 3000;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- INIT_WORK(&info->tqueue, mcfrs_offintr);
- INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
-
- info->imr = 0;
- mcfrs_setsignals(info, 0, 0);
- mcfrs_irqinit(info);
-
- printk("ttyS%d at 0x%04x (irq = %d)", info->line,
- (unsigned int) info->addr, info->irq);
- printk(" is a builtin ColdFire UART\n");
- }
-
- local_irq_restore(flags);
- return 0;
-}
-
-module_init(mcfrs_init);
-
-/****************************************************************************/
-/* Serial Console */
-/****************************************************************************/
-
-/*
- * Quick and dirty UART initialization, for console output.
- */
-
-void mcfrs_init_console(void)
-{
- volatile unsigned char *uartp;
- unsigned int clk;
-
- /*
- * Reset UART, get it into known state...
- */
- uartp = (volatile unsigned char *) (MCF_MBAR +
- (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
- uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */
-
- /*
- * Set port for defined baud , 8 data bits, 1 stop bit, no parity.
- */
- uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8;
- uartp[MCFUART_UMR] = MCFUART_MR2_STOP1;
-
-#ifdef CONFIG_M5272
-{
- /*
- * For the MCF5272, also compute the baudrate fraction.
- */
- int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud);
- fraction *= 16;
- fraction /= (32 * mcfrs_console_baud);
- uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */
- clk = (MCF_BUSCLK / mcfrs_console_baud) / 32;
-}
-#else
- clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */
-#endif
-
- uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */
- uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */
- uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
- uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
-
- mcfrs_console_inited++;
- return;
-}
-
-
-/*
- * Setup for console. Argument comes from the boot command line.
- */
-
-int mcfrs_console_setup(struct console *cp, char *arg)
-{
- int i, n = CONSOLE_BAUD_RATE;
-
- if (!cp)
- return(-1);
-
- if (!strncmp(cp->name, "ttyS", 4))
- mcfrs_console_port = cp->index;
- else if (!strncmp(cp->name, "cua", 3))
- mcfrs_console_port = cp->index;
- else
- return(-1);
-
- if (arg)
- n = simple_strtoul(arg,NULL,0);
- for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++)
- if (mcfrs_baud_table[i] == n)
- break;
- if (i < MCFRS_BAUD_TABLE_SIZE) {
- mcfrs_console_baud = n;
- mcfrs_console_cbaud = 0;
- if (i > 15) {
- mcfrs_console_cbaud |= CBAUDEX;
- i -= 15;
- }
- mcfrs_console_cbaud |= i;
- }
- mcfrs_init_console(); /* make sure baud rate changes */
- return(0);
-}
-
-
-static struct tty_driver *mcfrs_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return mcfrs_serial_driver;
-}
-
-
-/*
- * Output a single character, using UART polled mode.
- * This is used for console output.
- */
-
-int mcfrs_put_char(char ch)
-{
- volatile unsigned char *uartp;
- unsigned long flags;
- int i;
-
- uartp = (volatile unsigned char *) (MCF_MBAR +
- (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
-
- local_irq_save(flags);
- for (i = 0; (i < 0x10000); i++) {
- if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY)
- break;
- }
- if (i < 0x10000) {
- uartp[MCFUART_UTB] = ch;
- for (i = 0; (i < 0x10000); i++)
- if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)
- break;
- }
- if (i >= 0x10000)
- mcfrs_init_console(); /* try and get it back */
- local_irq_restore(flags);
-
- return 1;
-}
-
-
-/*
- * rs_console_write is registered for printk output.
- */
-
-void mcfrs_console_write(struct console *cp, const char *p, unsigned len)
-{
- if (!mcfrs_console_inited)
- mcfrs_init_console();
- while (len-- > 0) {
- if (*p == '\n')
- mcfrs_put_char('\r');
- mcfrs_put_char(*p++);
- }
-}
-
-/*
- * declare our consoles
- */
-
-struct console mcfrs_console = {
- .name = "ttyS",
- .write = mcfrs_console_write,
- .device = mcfrs_console_device,
- .setup = mcfrs_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-static int __init mcfrs_console_init(void)
-{
- register_console(&mcfrs_console);
- return 0;
-}
-
-console_initcall(mcfrs_console_init);
-
-/****************************************************************************/
diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
deleted file mode 100644
index 56420e2cb11..00000000000
--- a/drivers/serial/mcfserial.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * mcfserial.c -- serial driver for ColdFire internal UARTS.
- *
- * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com>
- * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com>
- * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com>
- *
- * Based on code from 68332serial.c which was:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 TSHG
- * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
- */
-#ifndef _MCF_SERIAL_H
-#define _MCF_SERIAL_H
-
-#include <linux/serial.h>
-
-#ifdef __KERNEL__
-
-/*
- * Define a local serial stats structure.
- */
-
-struct mcf_stats {
- unsigned int rx;
- unsigned int tx;
- unsigned int rxbreak;
- unsigned int rxframing;
- unsigned int rxparity;
- unsigned int rxoverrun;
-};
-
-
-/*
- * This is our internal structure for each serial port's state.
- * Each serial port has one of these structures associated with it.
- */
-
-struct mcf_serial {
- int magic;
- volatile unsigned char *addr; /* UART memory address */
- int irq;
- int flags; /* defined in tty.h */
- int type; /* UART type */
- struct tty_struct *tty;
- unsigned char imr; /* Software imr register */
- unsigned int baud;
- int sigs;
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int baud_base;
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- struct mcf_stats stats;
- struct work_struct tqueue;
- struct work_struct tqueue_hangup;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-
-};
-
-#endif /* __KERNEL__ */
-
-#endif /* _MCF_SERIAL_H */
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index f977c98cfa9..6bdf3362e3b 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
"transmitter\n",
port->dev ? port->dev->bus_id : "",
port->dev ? ": " : "",
- drv->dev_name, port->line);
+ drv->dev_name,
+ drv->tty_driver->name_base + port->line);
ops->shutdown(port);
}
@@ -2154,12 +2155,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
switch (port->iotype) {
case UPIO_PORT:
- snprintf(address, sizeof(address),
- "I/O 0x%x", port->iobase);
+ snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
break;
case UPIO_HUB6:
snprintf(address, sizeof(address),
- "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+ "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
break;
case UPIO_MEM:
case UPIO_MEM32:
@@ -2177,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
port->dev ? port->dev->bus_id : "",
port->dev ? ": " : "",
- drv->dev_name, port->line, address, port->irq, uart_type(port));
+ drv->dev_name,
+ drv->tty_driver->name_base + port->line,
+ address, port->irq, uart_type(port));
}
static void
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index e41766d0803..a94a2ab4b57 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -616,7 +616,7 @@ static int __devexit hv_remove(struct of_device *dev)
return 0;
}
-static struct of_device_id hv_match[] = {
+static const struct of_device_id hv_match[] = {
{
.name = "console",
.compatible = "qcn",
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 29b4458abf7..0355efe115d 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -1078,7 +1078,7 @@ static int __devexit sab_remove(struct of_device *op)
return 0;
}
-static struct of_device_id sab_match[] = {
+static const struct of_device_id sab_match[] = {
{
.name = "se",
},
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index a378464f929..a4dc79b1d7a 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1506,7 +1506,7 @@ static int __devexit su_remove(struct of_device *op)
return 0;
}
-static struct of_device_id su_match[] = {
+static const struct of_device_id su_match[] = {
{
.name = "su",
},
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 3cb4c8aee13..45a299f3561 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1480,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op)
return 0;
}
-static struct of_device_id zs_match[] = {
+static const struct of_device_id zs_match[] = {
{
.name = "zs",
},
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index db410e92c80..77fa7a08080 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -97,7 +97,7 @@ enum {
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_devuid, "devuid=%u"},
{Opt_devgid, "devgid=%u"},
{Opt_devmode, "devmode=%o"},
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 5799298364f..b697a13364e 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -210,143 +210,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
/*-------------------------------------------------------------------------*/
-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
-
-/* Section 2.2 Host Controller Capability Registers */
-struct ehci_caps {
- /* these fields are specified as 8 and 16 bit registers,
- * but some hosts can't perform 8 or 16 bit PCI accesses.
- */
- u32 hc_capbase;
-#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
-#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
- u32 hcs_params; /* HCSPARAMS - offset 0x4 */
-#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
-#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
-#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
-#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
-#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
-
- u32 hcc_params; /* HCCPARAMS - offset 0x8 */
-#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
-#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
-#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
-#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
- u8 portroute [8]; /* nibbles for routing - offset 0xC */
-} __attribute__ ((packed));
-
-
-/* Section 2.3 Host Controller Operational Registers */
-struct ehci_regs {
-
- /* USBCMD: offset 0x00 */
- u32 command;
-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
-#define CMD_PARK (1<<11) /* enable "park" on async qh */
-#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
-#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
-#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
-#define CMD_ASE (1<<5) /* async schedule enable */
-#define CMD_PSE (1<<4) /* periodic schedule enable */
-/* 3:2 is periodic frame list size */
-#define CMD_RESET (1<<1) /* reset HC not bus */
-#define CMD_RUN (1<<0) /* start/stop HC */
-
- /* USBSTS: offset 0x04 */
- u32 status;
-#define STS_ASS (1<<15) /* Async Schedule Status */
-#define STS_PSS (1<<14) /* Periodic Schedule Status */
-#define STS_RECL (1<<13) /* Reclamation */
-#define STS_HALT (1<<12) /* Not running (any reason) */
-/* some bits reserved */
- /* these STS_* flags are also intr_enable bits (USBINTR) */
-#define STS_IAA (1<<5) /* Interrupted on async advance */
-#define STS_FATAL (1<<4) /* such as some PCI access errors */
-#define STS_FLR (1<<3) /* frame list rolled over */
-#define STS_PCD (1<<2) /* port change detect */
-#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
-#define STS_INT (1<<0) /* "normal" completion (short, ...) */
-
- /* USBINTR: offset 0x08 */
- u32 intr_enable;
-
- /* FRINDEX: offset 0x0C */
- u32 frame_index; /* current microframe number */
- /* CTRLDSSEGMENT: offset 0x10 */
- u32 segment; /* address bits 63:32 if needed */
- /* PERIODICLISTBASE: offset 0x14 */
- u32 frame_list; /* points to periodic list */
- /* ASYNCLISTADDR: offset 0x18 */
- u32 async_next; /* address of next async queue head */
-
- u32 reserved [9];
-
- /* CONFIGFLAG: offset 0x40 */
- u32 configured_flag;
-#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
-
- /* PORTSC: offset 0x44 */
- u32 port_status [0]; /* up to N_PORTS */
-/* 31:23 reserved */
-#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
-#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
-#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
-/* 19:16 for port testing */
-#define PORT_LED_OFF (0<<14)
-#define PORT_LED_AMBER (1<<14)
-#define PORT_LED_GREEN (2<<14)
-#define PORT_LED_MASK (3<<14)
-#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
-#define PORT_POWER (1<<12) /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
-/* 9 reserved */
-#define PORT_RESET (1<<8) /* reset port */
-#define PORT_SUSPEND (1<<7) /* suspend port */
-#define PORT_RESUME (1<<6) /* resume it */
-#define PORT_OCC (1<<5) /* over current change */
-#define PORT_OC (1<<4) /* over current active */
-#define PORT_PEC (1<<3) /* port enable change */
-#define PORT_PE (1<<2) /* port enable */
-#define PORT_CSC (1<<1) /* connect status change */
-#define PORT_CONNECT (1<<0) /* device connected */
-#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
-} __attribute__ ((packed));
-
-#define USBMODE 0x68 /* USB Device mode */
-#define USBMODE_SDIS (1<<3) /* Stream disable */
-#define USBMODE_BE (1<<2) /* BE/LE endianness select */
-#define USBMODE_CM_HC (3<<0) /* host controller mode */
-#define USBMODE_CM_IDLE (0<<0) /* idle state */
-
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console. (nonstandard enumeration.)
- */
-struct ehci_dbg_port {
- u32 control;
-#define DBGP_OWNER (1<<30)
-#define DBGP_ENABLED (1<<28)
-#define DBGP_DONE (1<<16)
-#define DBGP_INUSE (1<<10)
-#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
-# define DBGP_ERR_BAD 1
-# define DBGP_ERR_SIGNAL 2
-#define DBGP_ERROR (1<<6)
-#define DBGP_GO (1<<5)
-#define DBGP_OUT (1<<4)
-#define DBGP_LEN(x) (((x)>>0)&0x0f)
- u32 pids;
-#define DBGP_PID_GET(x) (((x)>>16)&0xff)
-#define DBGP_PID_SET(data,tok) (((data)<<8)|(tok))
- u32 data03;
- u32 data47;
- u32 address;
-#define DBGP_EPADDR(dev,ep) (((dev)<<8)|(ep))
-} __attribute__ ((packed));
+#include <linux/usb/ehci_def.h>
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 79ea98c66fa..99fb7dc59c4 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work)
* 64 bytes, to ensure I do not get throttled.
* Ask USB mailing list for better aproach.
*/
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (!tty) {
schedule_work(&priv->rx_work);
@@ -283,12 +283,13 @@ static void aircable_read(struct work_struct *work)
count = min(64, serial_buf_data_avail(priv->rx_buf));
if (count <= 0)
- return; /* We have finished sending everything. */
+ goto out; /* We have finished sending everything. */
tty_prepare_flip_string(tty, &data, count);
if (!data) {
- err("%s- kzalloc(%d) failed.", __func__, count);
- return;
+ dev_err(&port->dev, "%s- kzalloc(%d) failed.",
+ __func__, count);
+ goto out;
}
serial_buf_get(priv->rx_buf, data, count);
@@ -297,7 +298,8 @@ static void aircable_read(struct work_struct *work)
if (serial_buf_data_avail(priv->rx_buf))
schedule_work(&priv->rx_work);
-
+out:
+ tty_kref_put(tty);
return;
}
/* End of private methods */
@@ -495,7 +497,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, urb->transfer_buffer);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
if (urb->actual_length <= 2) {
/* This is an incomplete package */
@@ -527,6 +529,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
}
aircable_read(&priv->rx_work);
}
+ tty_kref_put(tty);
/* Schedule the next read _if_ we are still open */
if (port->port.count) {
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 2ebe06c3405..1913bc7c5f0 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
* to look in to this before committing any code.
*/
if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
/* Overrun Error */
if (priv->last_lsr & BELKIN_SA_LSR_OE) {
}
@@ -335,6 +335,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
/* Break Indicator */
if (priv->last_lsr & BELKIN_SA_LSR_BI) {
}
+ tty_kref_put(tty);
}
#endif
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index e980766bb84..5b20de130e0 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
}
port = serial->port[0];
- port->port.tty = NULL;
+ tty_port_tty_set(&port->port, NULL);
info->port = port;
@@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
}
memset(&dummy, 0, sizeof(struct ktermios));
tty->termios = termios;
- port->port.tty = tty;
+ tty_port_tty_set(&port->port, tty);
}
/* only call the device specific open if this
@@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
tty_termios_encode_baud_rate(termios, baud, baud);
serial->type->set_termios(tty, port, &dummy);
- port->port.tty = NULL;
+ tty_port_tty_set(&port->port, NULL);
kfree(termios);
kfree(tty);
}
@@ -176,7 +176,7 @@ out:
return retval;
free_termios:
kfree(termios);
- port->port.tty = NULL;
+ tty_port_tty_set(&port->port, NULL);
free_tty:
kfree(tty);
reset_open_count:
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index b4d72351cb9..94ef36c4764 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
return;
}
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (!tty) {
dbg("%s - ignoring since device not open\n", __func__);
return;
@@ -394,6 +394,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
spin_lock(&priv->lock);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 22837a3f2f8..f3514a91f91 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb)
}
spin_unlock_irqrestore(&priv->lock, flags);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (!tty) {
dbg("%s - bad tty pointer - exiting", __func__);
return;
@@ -1362,7 +1362,7 @@ static void cypress_read_int_callback(struct urb *urb)
data[i]);
tty_insert_flip_char(tty, data[i], tty_flag);
}
- tty_flip_buffer_push(port->port.tty);
+ tty_flip_buffer_push(tty);
}
spin_lock_irqsave(&priv->lock, flags);
@@ -1371,6 +1371,7 @@ static void cypress_read_int_callback(struct urb *urb)
spin_unlock_irqrestore(&priv->lock, flags);
continue_read:
+ tty_kref_put(tty);
/* Continue trying to always read... unless the port has closed. */
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 240aad1acaa..5756ac6d6c9 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -604,7 +604,9 @@ static void digi_wakeup_write_lock(struct work_struct *work)
static void digi_wakeup_write(struct usb_serial_port *port)
{
- tty_wakeup(port->port.tty);
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
@@ -1668,7 +1670,7 @@ static int digi_read_inb_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct tty_struct *tty = port->port.tty;
+ struct tty_struct *tty;
struct digi_port *priv = usb_get_serial_port_data(port);
int opcode = ((unsigned char *)urb->transfer_buffer)[0];
int len = ((unsigned char *)urb->transfer_buffer)[1];
@@ -1692,6 +1694,7 @@ static int digi_read_inb_callback(struct urb *urb)
return -1;
}
+ tty = tty_port_tty_get(&port->port);
spin_lock(&priv->dp_port_lock);
/* check for throttle; if set, do not resubmit read urb */
@@ -1735,6 +1738,7 @@ static int digi_read_inb_callback(struct urb *urb)
}
}
spin_unlock(&priv->dp_port_lock);
+ tty_kref_put(tty);
if (opcode == DIGI_CMD_RECEIVE_DISABLE)
dbg("%s: got RECEIVE_DISABLE", __func__);
@@ -1760,6 +1764,7 @@ static int digi_read_oob_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct usb_serial *serial = port->serial;
+ struct tty_struct *tty;
struct digi_port *priv = usb_get_serial_port_data(port);
int opcode, line, status, val;
int i;
@@ -1787,10 +1792,11 @@ static int digi_read_oob_callback(struct urb *urb)
if (priv == NULL)
return -1;
+ tty = tty_port_tty_get(&port->port);
rts = 0;
if (port->port.count)
- rts = port->port.tty->termios->c_cflag & CRTSCTS;
-
+ rts = tty->termios->c_cflag & CRTSCTS;
+
if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
spin_lock(&priv->dp_port_lock);
/* convert from digi flags to termiox flags */
@@ -1798,14 +1804,14 @@ static int digi_read_oob_callback(struct urb *urb)
priv->dp_modem_signals |= TIOCM_CTS;
/* port must be open to use tty struct */
if (rts) {
- port->port.tty->hw_stopped = 0;
+ tty->hw_stopped = 0;
digi_wakeup_write(port);
}
} else {
priv->dp_modem_signals &= ~TIOCM_CTS;
/* port must be open to use tty struct */
if (rts)
- port->port.tty->hw_stopped = 1;
+ tty->hw_stopped = 1;
}
if (val & DIGI_READ_INPUT_SIGNALS_DSR)
priv->dp_modem_signals |= TIOCM_DSR;
@@ -1830,6 +1836,7 @@ static int digi_read_oob_callback(struct urb *urb)
} else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
wake_up_interruptible(&priv->dp_flush_wait);
}
+ tty_kref_put(tty);
}
return 0;
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index a6ab5b58d9c..1072e847280 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -33,9 +33,8 @@
* Moved MOD_DEC_USE_COUNT to end of empeg_close().
*
* (12/03/2000) gb
- * Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to
- * empeg_open(). This notifies the tty driver that the termios have
- * changed.
+ * Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
+ * This notifies the tty driver that the termios have changed.
*
* (11/13/2000) gb
* Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
@@ -354,7 +353,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length);
@@ -362,6 +361,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
tty_flip_buffer_push(tty);
bytes_in += urb->actual_length;
}
+ tty_kref_put(tty);
/* Continue trying to always read */
usb_fill_bulk_urb(
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 3dc93b542b3..c2ac129557a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
kfree(buf);
if (rv < 0) {
- err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+ dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
__func__,
(set & TIOCM_DTR) ? "HIGH" :
(clear & TIOCM_DTR) ? "LOW" : "unchanged",
@@ -1808,7 +1808,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
if (port->port.count <= 0)
return;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (!tty) {
dbg("%s - bad tty pointer - exiting", __func__);
return;
@@ -1817,7 +1817,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
priv = usb_get_serial_port_data(port);
if (!priv) {
dbg("%s - bad port private data pointer - exiting", __func__);
- return;
+ goto out;
}
if (urb != port->read_urb)
@@ -1827,7 +1827,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
/* This will happen at close every time so it is a dbg not an
err */
dbg("(this is ok on close) nonzero read bulk status received: %d", status);
- return;
+ goto out;
}
/* count data bytes, but not status bytes */
@@ -1838,7 +1838,8 @@ static void ftdi_read_bulk_callback(struct urb *urb)
spin_unlock_irqrestore(&priv->rx_lock, flags);
ftdi_process_read(&priv->rx_work.work);
-
+out:
+ tty_kref_put(tty);
} /* ftdi_read_bulk_callback */
@@ -1863,7 +1864,7 @@ static void ftdi_process_read(struct work_struct *work)
if (port->port.count <= 0)
return;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (!tty) {
dbg("%s - bad tty pointer - exiting", __func__);
return;
@@ -1872,13 +1873,13 @@ static void ftdi_process_read(struct work_struct *work)
priv = usb_get_serial_port_data(port);
if (!priv) {
dbg("%s - bad port private data pointer - exiting", __func__);
- return;
+ goto out;
}
urb = port->read_urb;
if (!urb) {
dbg("%s - bad read_urb pointer - exiting", __func__);
- return;
+ goto out;
}
data = urb->transfer_buffer;
@@ -2020,7 +2021,7 @@ static void ftdi_process_read(struct work_struct *work)
schedule_delayed_work(&priv->rx_work, 1);
else
dbg("%s - port is closed", __func__);
- return;
+ goto out;
}
/* urb is completely processed */
@@ -2041,6 +2042,8 @@ static void ftdi_process_read(struct work_struct *work)
err("%s - failed resubmitting read urb, error %d",
__func__, result);
}
+out:
+ tty_kref_put(tty);
} /* ftdi_process_read */
@@ -2256,7 +2259,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
0, 0,
buf, 1, WDR_TIMEOUT);
if (ret < 0) {
- err("%s Could not get modem status of device - err: %d", __func__,
+ dbg("%s Could not get modem status of device - err: %d", __func__,
ret);
return ret;
}
@@ -2275,7 +2278,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
0, priv->interface,
buf, 2, WDR_TIMEOUT);
if (ret < 0) {
- err("%s Could not get modem status of device - err: %d", __func__,
+ dbg("%s Could not get modem status of device - err: %d", __func__,
ret);
return ret;
}
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index d9538208807..2ad0569bcf1 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -276,7 +276,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
static void send_to_tty(struct usb_serial_port *port,
char *data, unsigned int actual_length)
{
- struct tty_struct *tty = port->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
if (tty && actual_length) {
@@ -287,6 +287,7 @@ static void send_to_tty(struct usb_serial_port *port,
tty_insert_flip_string(tty, data, actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
}
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index fe84c88ec20..814909f1ee6 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -330,7 +330,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
{
struct urb *urb = port->read_urb;
- struct tty_struct *tty = port->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
int room;
/* Push data to tty */
@@ -341,6 +341,7 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
tty_flip_buffer_push(tty);
}
}
+ tty_kref_put(tty);
resubmit_read_urb(port, GFP_ATOMIC);
}
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index bfa508ddb0f..611f97fd62f 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -600,6 +600,7 @@ static void edge_interrupt_callback(struct urb *urb)
struct edgeport_serial *edge_serial = urb->context;
struct edgeport_port *edge_port;
struct usb_serial_port *port;
+ struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int length = urb->actual_length;
int bytes_avail;
@@ -675,9 +676,12 @@ static void edge_interrupt_callback(struct urb *urb)
/* tell the tty driver that something
has changed */
- if (edge_port->port->port.tty)
- tty_wakeup(edge_port->port->port.tty);
-
+ tty = tty_port_tty_get(
+ &edge_port->port->port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
/* Since we have more credit, check
if more data can be sent */
send_more_port_data(edge_serial,
@@ -778,13 +782,14 @@ static void edge_bulk_out_data_callback(struct urb *urb)
__func__, status);
}
- tty = edge_port->port->port.tty;
+ tty = tty_port_tty_get(&edge_port->port->port);
if (tty && edge_port->open) {
/* let the tty driver wakeup if it has a special
write_wakeup function */
tty_wakeup(tty);
}
+ tty_kref_put(tty);
/* Release the Write URB */
edge_port->write_in_progress = false;
@@ -826,11 +831,12 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
}
/* Get pointer to tty */
- tty = edge_port->port->port.tty;
+ tty = tty_port_tty_get(&edge_port->port->port);
/* tell the tty driver that something has changed */
if (tty && edge_port->open)
tty_wakeup(tty);
+ tty_kref_put(tty);
/* we have completed the command */
edge_port->commandPending = false;
@@ -1932,11 +1938,13 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
edge_serial->rxPort];
edge_port = usb_get_serial_port_data(port);
if (edge_port->open) {
- tty = edge_port->port->port.tty;
+ tty = tty_port_tty_get(
+ &edge_port->port->port);
if (tty) {
dbg("%s - Sending %d bytes to TTY for port %d",
__func__, rxLen, edge_serial->rxPort);
edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
+ tty_kref_put(tty);
}
edge_port->icount.rx += rxLen;
}
@@ -1971,6 +1979,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
{
struct usb_serial_port *port;
struct edgeport_port *edge_port;
+ struct tty_struct *tty;
__u8 code = edge_serial->rxStatusCode;
/* switch the port pointer to the one being currently talked about */
@@ -2020,10 +2029,12 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
/* send the current line settings to the port so we are
in sync with any further termios calls */
- /* FIXME: locking on tty */
- if (edge_port->port->port.tty)
- change_port_settings(edge_port->port->port.tty,
- edge_port, edge_port->port->port.tty->termios);
+ tty = tty_port_tty_get(&edge_port->port->port);
+ if (tty) {
+ change_port_settings(tty,
+ edge_port, tty->termios);
+ tty_kref_put(tty);
+ }
/* we have completed the open */
edge_port->openPending = false;
@@ -2163,10 +2174,14 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
}
/* Place LSR data byte into Rx buffer */
- if (lsrData && edge_port->port->port.tty)
- edge_tty_recv(&edge_port->port->dev,
- edge_port->port->port.tty, &data, 1);
-
+ if (lsrData) {
+ struct tty_struct *tty =
+ tty_port_tty_get(&edge_port->port->port);
+ if (tty) {
+ edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+ tty_kref_put(tty);
+ }
+ }
/* update input line counters */
icount = &edge_port->icount;
if (newLsr & LSR_BREAK)
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index cb4c54316cf..541dd8e6e7a 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
int flush)
{
int baud_rate;
- struct tty_struct *tty = port->port->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->port->port);
wait_queue_t wait;
unsigned long flags;
@@ -599,6 +599,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
if (flush)
edge_buf_clear(port->ep_out_buf);
spin_unlock_irqrestore(&port->ep_lock, flags);
+ tty_kref_put(tty);
/* wait for data to drain from the device */
timeout += jiffies;
@@ -1554,7 +1555,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
/* Save the new modem status */
edge_port->shadow_msr = msr & 0xf0;
- tty = edge_port->port->port.tty;
+ tty = tty_port_tty_get(&edge_port->port->port);
/* handle CTS flow control */
if (tty && C_CRTSCTS(tty)) {
if (msr & EDGEPORT_MSR_CTS) {
@@ -1564,6 +1565,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
tty->hw_stopped = 1;
}
}
+ tty_kref_put(tty);
return;
}
@@ -1574,6 +1576,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
struct async_icount *icount;
__u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
LSR_FRM_ERR | LSR_BREAK));
+ struct tty_struct *tty;
dbg("%s - %02x", __func__, new_lsr);
@@ -1587,8 +1590,13 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
/* Place LSR data byte into Rx buffer */
- if (lsr_data && edge_port->port->port.tty)
- edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1);
+ if (lsr_data) {
+ tty = tty_port_tty_get(&edge_port->port->port);
+ if (tty) {
+ edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+ tty_kref_put(tty);
+ }
+ }
/* update input line counters */
icount = &edge_port->icount;
@@ -1749,7 +1757,7 @@ static void edge_bulk_in_callback(struct urb *urb)
++data;
}
- tty = edge_port->port->port.tty;
+ tty = tty_port_tty_get(&edge_port->port->port);
if (tty && urb->actual_length) {
usb_serial_debug_data(debug, &edge_port->port->dev,
__func__, urb->actual_length, data);
@@ -1761,6 +1769,7 @@ static void edge_bulk_in_callback(struct urb *urb)
urb->actual_length);
edge_port->icount.rx += urb->actual_length;
}
+ tty_kref_put(tty);
exit:
/* continue read unless stopped */
@@ -1796,6 +1805,7 @@ static void edge_bulk_out_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int status = urb->status;
+ struct tty_struct *tty;
dbg("%s - port %d", __func__, port->number);
@@ -1818,7 +1828,9 @@ static void edge_bulk_out_callback(struct urb *urb)
}
/* send any buffered data */
- edge_send(port->port.tty);
+ tty = tty_port_tty_get(&port->port);
+ edge_send(tty);
+ tty_kref_put(tty);
}
static int edge_open(struct tty_struct *tty,
@@ -1876,7 +1888,7 @@ static int edge_open(struct tty_struct *tty,
/* set up the port settings */
if (tty)
- edge_set_termios(tty, port, port->port.tty->termios);
+ edge_set_termios(tty, port, tty->termios);
/* open up the port */
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index cd9a2e138c8..2affa9c118b 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -764,13 +764,14 @@ static void ipaq_read_bulk_callback(struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
bytes_in += urb->actual_length;
}
+ tty_kref_put(tty);
/* Continue trying to always read */
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index a842025b9b5..480cac27d64 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -170,12 +170,13 @@ static void ipw_read_bulk_callback(struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* Continue trying to always read */
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index e59155c6607..45d4043e04a 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -465,11 +465,12 @@ static void ir_read_bulk_callback(struct urb *urb)
ir_baud = *data & 0x0f;
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/*
* No break here.
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index ddff37fa633..53710aa7ead 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -629,13 +629,14 @@ static void read_buf_callback(struct urb *urb)
}
dbg("%s - %i chars to write", __func__, urb->actual_length);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (data == NULL)
dbg("%s - data is NULL !!!", __func__);
if (tty && urb->actual_length && data) {
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
iuu_led_activity_on(urb);
}
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 704716f6f6d..15447af4869 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -430,7 +430,7 @@ static void usa26_indat_callback(struct urb *urb)
}
port = urb->context;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
@@ -459,6 +459,7 @@ static void usa26_indat_callback(struct urb *urb)
}
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
@@ -513,6 +514,7 @@ static void usa26_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
+ struct tty_struct *tty;
int old_dcd_state, err;
int status = urb->status;
@@ -553,12 +555,11 @@ static void usa26_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (port->port.tty && !C_CLOCAL(port->port.tty)
- && old_dcd_state != p_priv->dcd_state) {
- if (old_dcd_state)
- tty_hangup(port->port.tty);
- /* else */
- /* wake_up_interruptible(&p_priv->open_wait); */
+ if (old_dcd_state != p_priv->dcd_state) {
+ tty = tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
+ tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */
@@ -604,11 +605,12 @@ static void usa28_indat_callback(struct urb *urb)
p_priv = usb_get_serial_port_data(port);
data = urb->transfer_buffer;
- tty = port->port.tty;
- if (urb->actual_length) {
+ tty =tty_port_tty_get(&port->port);
+ if (tty && urb->actual_length) {
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
@@ -652,6 +654,7 @@ static void usa28_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
+ struct tty_struct *tty;
int old_dcd_state;
int status = urb->status;
@@ -689,12 +692,11 @@ static void usa28_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (port->port.tty && !C_CLOCAL(port->port.tty)
- && old_dcd_state != p_priv->dcd_state) {
- if (old_dcd_state)
- tty_hangup(port->port.tty);
- /* else */
- /* wake_up_interruptible(&p_priv->open_wait); */
+ if( old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+ tty = tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
+ tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */
@@ -785,12 +787,11 @@ static void usa49_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (port->port.tty && !C_CLOCAL(port->port.tty)
- && old_dcd_state != p_priv->dcd_state) {
- if (old_dcd_state)
- tty_hangup(port->port.tty);
- /* else */
- /* wake_up_interruptible(&p_priv->open_wait); */
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
+ tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */
@@ -827,7 +828,7 @@ static void usa49_indat_callback(struct urb *urb)
}
port = urb->context;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
@@ -850,6 +851,7 @@ static void usa49_indat_callback(struct urb *urb)
}
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
urb->dev = port->serial->dev;
@@ -893,7 +895,7 @@ static void usa49wg_indat_callback(struct urb *urb)
return;
}
port = serial->port[data[i++]];
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
len = data[i++];
/* 0x80 bit is error flag */
@@ -927,6 +929,7 @@ static void usa49wg_indat_callback(struct urb *urb)
}
if (port->port.count)
tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
}
}
@@ -967,8 +970,8 @@ static void usa90_indat_callback(struct urb *urb)
port = urb->context;
p_priv = usb_get_serial_port_data(port);
- tty = port->port.tty;
if (urb->actual_length) {
+ tty = tty_port_tty_get(&port->port);
/* if current mode is DMA, looks like usa28 format
otherwise looks like usa26 data format */
@@ -1004,6 +1007,7 @@ static void usa90_indat_callback(struct urb *urb)
}
}
tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */
@@ -1025,6 +1029,7 @@ static void usa90_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
+ struct tty_struct *tty;
int old_dcd_state, err;
int status = urb->status;
@@ -1053,12 +1058,11 @@ static void usa90_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (port->port.tty && !C_CLOCAL(port->port.tty)
- && old_dcd_state != p_priv->dcd_state) {
- if (old_dcd_state)
- tty_hangup(port->port.tty);
- /* else */
- /* wake_up_interruptible(&p_priv->open_wait); */
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+ tty = tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
+ tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */
@@ -1130,12 +1134,11 @@ static void usa67_instat_callback(struct urb *urb)
p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
- if (port->port.tty && !C_CLOCAL(port->port.tty)
- && old_dcd_state != p_priv->dcd_state) {
- if (old_dcd_state)
- tty_hangup(port->port.tty);
- /* else */
- /* wake_up_interruptible(&p_priv->open_wait); */
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
+ tty_kref_put(tty);
}
/* Resubmit urb so we continue receiving */
@@ -1332,7 +1335,7 @@ static void keyspan_close(struct tty_struct *tty,
stop_urb(p_priv->out_urbs[i]);
}
}
- port->port.tty = NULL;
+ tty_port_tty_set(&port->port, NULL);
}
/* download the firmware to a pre-renumeration device */
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 040040a267d..99e9a14c5bf 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -172,8 +172,9 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
struct keyspan_pda_private *priv =
container_of(work, struct keyspan_pda_private, wakeup_work);
struct usb_serial_port *port = priv->port;
-
- tty_wakeup(port->port.tty);
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -205,7 +206,7 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
static void keyspan_pda_rx_interrupt(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct tty_struct *tty = port->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
unsigned char *data = urb->transfer_buffer;
int retval;
int status = urb->status;
@@ -222,7 +223,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__func__, status);
- return;
+ goto out;
default:
dbg("%s - nonzero urb status received: %d",
__func__, status);
@@ -261,8 +262,11 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(&port->dev,
+ "%s - usb_submit_urb failed with result %d",
+ __func__, retval);
+out:
+ tty_kref_put(tty);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index b84dddc7112..ff3a07f5102 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -658,7 +658,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
} else {
int bytes_sent = ((__u8 *) data)[0] +
((unsigned int) ((__u8 *) data)[1] << 8);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
/* we should immediately resubmit the URB, before attempting
* to pass the data on to the tty layer. But that needs locking
* against re-entry an then mixed-up data because of
@@ -679,6 +679,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
tty_buffer_request_room(tty, bytes_sent);
tty_insert_flip_string(tty, data + 2, bytes_sent);
tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
/* again lockless, but debug info only */
priv->bytes_in += bytes_sent;
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index deba28ec77e..cfcf37c2b95 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb)
return;
}
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (urb->actual_length) {
/* BEGIN DEBUG */
@@ -405,6 +405,7 @@ static void kobil_read_int_callback(struct urb *urb)
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* someone sets the dev to 0 if the close method has been called */
port->interrupt_in_urb->dev = port->serial->dev;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 0ded8bd6ec8..9b2cef81cde 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -563,10 +563,11 @@ static void mct_u232_read_int_callback(struct urb *urb)
* Work-a-round: handle the 'usual' bulk-in pipe here
*/
if (urb->transfer_buffer_length > 2) {
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (urb->actual_length) {
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
}
goto exit;
}
@@ -591,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
* to look in to this before committing any code.
*/
if (priv->last_lsr & MCT_U232_LSR_ERR) {
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
/* Overrun Error */
if (priv->last_lsr & MCT_U232_LSR_OE) {
}
@@ -604,6 +605,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
/* Break Indicator */
if (priv->last_lsr & MCT_U232_LSR_BI) {
}
+ tty_kref_put(tty);
}
#endif
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 7c4917d77c0..7b538caec37 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -216,12 +216,13 @@ static void mos7720_bulk_in_callback(struct urb *urb)
data = urb->transfer_buffer;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
if (!port->read_urb) {
dbg("URB KILLED !!!");
@@ -262,10 +263,11 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
dbg("Entering .........");
- tty = mos7720_port->port->port.tty;
+ tty = tty_port_tty_get(&mos7720_port->port->port);
if (tty && mos7720_port->open)
tty_wakeup(tty);
+ tty_kref_put(tty);
}
/*
@@ -1267,29 +1269,6 @@ static int get_lsr_info(struct tty_struct *tty,
return 0;
}
-/*
- * get_number_bytes_avail - get number of bytes available
- *
- * Purpose: Let user call ioctl to get the count of number of bytes available.
- */
-static int get_number_bytes_avail(struct moschip_port *mos7720_port,
- unsigned int __user *value)
-{
- unsigned int result = 0;
- struct tty_struct *tty = mos7720_port->port->port.tty;
-
- if (!tty)
- return -ENOIOCTLCMD;
-
- result = tty->read_cnt;
-
- dbg("%s(%d) = %d", __func__, mos7720_port->port->number, result);
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
-
- return -ENOIOCTLCMD;
-}
-
static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
unsigned int __user *value)
{
@@ -1409,13 +1388,6 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file,
dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
switch (cmd) {
- case TIOCINQ:
- /* return number of bytes available */
- dbg("%s (%d) TIOCINQ", __func__, port->number);
- return get_number_bytes_avail(mos7720_port,
- (unsigned int __user *)arg);
- break;
-
case TIOCSERGETLSR:
dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
return get_lsr_info(tty, mos7720_port,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 09d82062b97..60543d79ef5 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -709,12 +709,13 @@ static void mos7840_bulk_in_callback(struct urb *urb)
dbg("%s", "Entering ........... \n");
if (urb->actual_length) {
- tty = mos7840_port->port->port.tty;
+ tty = tty_port_tty_get(&mos7840_port->port->port);
if (tty) {
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
dbg(" %s \n", data);
tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
}
mos7840_port->icount.rx += urb->actual_length;
smp_wmb();
@@ -773,10 +774,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
dbg("%s \n", "Entering .........");
- tty = mos7840_port->port->port.tty;
-
+ tty = tty_port_tty_get(&mos7840_port->port->port);
if (tty && mos7840_port->open)
tty_wakeup(tty);
+ tty_kref_put(tty);
}
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index d6736531a0f..bcdcbb82270 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -64,12 +64,13 @@ static void navman_read_int_callback(struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
exit:
result = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index ae8e227f3db..c4d70b0f1e4 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number);
wport = serial->port[1];
- wport->port.tty = tty; /* FIXME */
+ tty_port_tty_set(&wport->port, tty);
/* Start reading from the device */
usb_fill_bulk_urb(port->read_urb, serial->dev,
@@ -229,9 +229,11 @@ static void omninet_read_bulk_callback(struct urb *urb)
}
if (urb->actual_length && header->oh_len) {
- tty_insert_flip_string(port->port.tty,
- data + OMNINET_DATAOFFSET, header->oh_len);
- tty_flip_buffer_push(port->port.tty);
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
+ header->oh_len);
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
}
/* Continue trying to always read */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 73f8277f88f..6b1727e751e 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -571,14 +571,14 @@ static void option_indat_callback(struct urb *urb)
dbg("%s: nonzero status: %d on endpoint %02x.",
__func__, status, endpoint);
} else {
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
- } else {
+ } else
dbg("%s: empty read urb received", __func__);
- }
+ tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
if (port->port.count && status != -ESHUTDOWN) {
@@ -647,9 +647,13 @@ static void option_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
- if (port->port.tty && !C_CLOCAL(port->port.tty) &&
- old_dcd_state && !portdata->dcd_state)
- tty_hangup(port->port.tty);
+ if (old_dcd_state && !portdata->dcd_state) {
+ struct tty_struct *tty =
+ tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
} else {
dbg("%s: type %x req %x", __func__,
req_pkt->bRequestType, req_pkt->bRequest);
@@ -793,7 +797,7 @@ static void option_close(struct tty_struct *tty,
for (i = 0; i < N_OUT_URB; i++)
usb_kill_urb(portdata->out_urbs[i]);
}
- port->port.tty = NULL; /* FIXME */
+ tty_port_tty_set(&port->port, NULL);
}
/* Helper functions used by option_setup_urbs */
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 81db5715ee2..ba551f00f16 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -224,10 +224,6 @@ struct oti6858_private {
struct usb_serial_port *port; /* USB port with which associated */
};
-#undef dbg
-/* #define dbg(format, arg...) printk(KERN_INFO "%s: " format "\n", __FILE__, ## arg) */
-#define dbg(format, arg...) printk(KERN_INFO "" format "\n", ## arg)
-
static void setup_line(struct work_struct *work)
{
struct oti6858_private *priv = container_of(work,
@@ -1002,11 +998,12 @@ static void oti6858_read_bulk_callback(struct urb *urb)
return;
}
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty != NULL && urb->actual_length > 0) {
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* schedule the interrupt urb if we are still open */
if (port->port.count != 0) {
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1ede1441cb1..90843784716 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -154,7 +154,6 @@ struct pl2303_private {
wait_queue_head_t delta_msr_wait;
u8 line_control;
u8 line_status;
- u8 termios_initialized;
enum pl2303_type type;
};
@@ -526,16 +525,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
- if (!priv->termios_initialized) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
- priv->termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
/* The PL2303 is reported to lose bytes if you change
serial settings even to the same values as before. Thus
we actually need to filter in this specific case */
@@ -1057,7 +1046,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
tty_flag = TTY_FRAME;
dbg("%s - tty_flag = %d", __func__, tty_flag);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length + 1);
/* overrun is special, not associated with a char */
@@ -1067,7 +1056,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
tty_insert_flip_char(tty, data[i], tty_flag);
tty_flip_buffer_push(tty);
}
-
+ tty_kref_put(tty);
/* Schedule the next read _if_ we are still open */
if (port->port.count) {
urb->dev = port->serial->dev;
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index def52d07a4e..72903ac9f5c 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -217,6 +217,7 @@ static void safe_read_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
unsigned char length = urb->actual_length;
+ struct tty_struct *tty;
int result;
int status = urb->status;
@@ -242,6 +243,7 @@ static void safe_read_bulk_callback(struct urb *urb)
printk("\n");
}
#endif
+ tty = tty_port_tty_get(&port->port);
if (safe) {
__u16 fcs;
fcs = fcs_compute10(data, length, CRC10_INITFCS);
@@ -250,9 +252,9 @@ static void safe_read_bulk_callback(struct urb *urb)
if (actual_length <= (length - 2)) {
info("%s - actual: %d", __func__,
actual_length);
- tty_insert_flip_string(port->port.tty,
+ tty_insert_flip_string(tty,
data, actual_length);
- tty_flip_buffer_push(port->port.tty);
+ tty_flip_buffer_push(tty);
} else {
err("%s - inconsistent lengths %d:%d",
__func__, actual_length, length);
@@ -261,9 +263,10 @@ static void safe_read_bulk_callback(struct urb *urb)
err("%s - bad CRC %x", __func__, fcs);
}
} else {
- tty_insert_flip_string(port->port.tty, data, length);
- tty_flip_buffer_push(port->port.tty);
+ tty_insert_flip_string(tty, data, length);
+ tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* Continue trying to always read */
usb_fill_bulk_urb(urb, port->serial->dev,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index ea1a103c99b..8b9eaf38367 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -440,14 +440,14 @@ static void sierra_indat_callback(struct urb *urb)
dbg("%s: nonzero status: %d on endpoint %02x.",
__func__, status, endpoint);
} else {
- tty = port->port.tty;
if (urb->actual_length) {
+ tty = tty_port_tty_get(&port->port);
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
- } else {
+ tty_kref_put(tty);
+ } else
dbg("%s: empty read urb received", __func__);
- }
/* Resubmit urb so we continue receiving */
if (port->port.count && status != -ESHUTDOWN) {
@@ -485,6 +485,7 @@ static void sierra_instat_callback(struct urb *urb)
unsigned char signals = *((unsigned char *)
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
+ struct tty_struct *tty;
dbg("%s: signal x%x", __func__, signals);
@@ -494,9 +495,11 @@ static void sierra_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
- if (port->port.tty && !C_CLOCAL(port->port.tty) &&
+ tty = tty_port_tty_get(&port->port);
+ if (tty && !C_CLOCAL(tty) &&
old_dcd_state && !portdata->dcd_state)
- tty_hangup(port->port.tty);
+ tty_hangup(tty);
+ tty_kref_put(tty);
} else {
dbg("%s: type %x req %x", __func__,
req_pkt->bRequestType, req_pkt->bRequest);
@@ -616,8 +619,7 @@ static void sierra_close(struct tty_struct *tty,
}
usb_kill_urb(port->interrupt_in_urb);
-
- port->port.tty = NULL; /* FIXME */
+ tty_port_tty_set(&port->port, NULL);
}
static int sierra_startup(struct usb_serial *serial)
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 283cf6b36b2..1533d6e1223 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -755,7 +755,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
tty_flag = TTY_FRAME;
dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (tty && urb->actual_length) {
tty_buffer_request_room(tty, urb->actual_length + 1);
/* overrun is special, not associated with a char */
@@ -765,6 +765,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
tty_insert_flip_char(tty, data[i], tty_flag);
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
/* Schedule the next read _if_ we are still open */
if (port->port.count) {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 9a3e495c769..c90237d48b0 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -179,7 +179,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);
static int ti_get_lsr(struct ti_port *tport);
static int ti_get_serial_info(struct ti_port *tport,
struct serial_struct __user *ret_arg);
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
struct serial_struct __user *new_arg);
static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);
@@ -857,8 +857,8 @@ static int ti_ioctl(struct tty_struct *tty, struct file *file,
(struct serial_struct __user *)arg);
case TIOCSSERIAL:
dbg("%s - (%d) TIOCSSERIAL", __func__, port->number);
- return ti_set_serial_info(tport,
- (struct serial_struct __user *)arg);
+ return ti_set_serial_info(tty, tport,
+ (struct serial_struct __user *)arg);
case TIOCMIWAIT:
dbg("%s - (%d) TIOCMIWAIT", __func__, port->number);
cprev = tport->tp_icount;
@@ -1211,6 +1211,7 @@ static void ti_bulk_in_callback(struct urb *urb)
struct device *dev = &urb->dev->dev;
int status = urb->status;
int retval = 0;
+ struct tty_struct *tty;
dbg("%s", __func__);
@@ -1239,20 +1240,22 @@ static void ti_bulk_in_callback(struct urb *urb)
return;
}
- if (port->port.tty && urb->actual_length) {
+ tty = tty_port_tty_get(&port->port);
+ if (tty && urb->actual_length) {
usb_serial_debug_data(debug, dev, __func__,
urb->actual_length, urb->transfer_buffer);
if (!tport->tp_is_open)
dbg("%s - port closed, dropping data", __func__);
else
- ti_recv(&urb->dev->dev, port->port.tty,
+ ti_recv(&urb->dev->dev, tty,
urb->transfer_buffer,
urb->actual_length);
spin_lock(&tport->tp_lock);
tport->tp_icount.rx += urb->actual_length;
spin_unlock(&tport->tp_lock);
+ tty_kref_put(tty);
}
exit:
@@ -1330,7 +1333,7 @@ static void ti_send(struct ti_port *tport)
{
int count, result;
struct usb_serial_port *port = tport->tp_port;
- struct tty_struct *tty = port->port.tty; /* FIXME */
+ struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
unsigned long flags;
@@ -1338,19 +1341,15 @@ static void ti_send(struct ti_port *tport)
spin_lock_irqsave(&tport->tp_lock, flags);
- if (tport->tp_write_urb_in_use) {
- spin_unlock_irqrestore(&tport->tp_lock, flags);
- return;
- }
+ if (tport->tp_write_urb_in_use)
+ goto unlock;
count = ti_buf_get(tport->tp_write_buf,
port->write_urb->transfer_buffer,
port->bulk_out_size);
- if (count == 0) {
- spin_unlock_irqrestore(&tport->tp_lock, flags);
- return;
- }
+ if (count == 0)
+ goto unlock;
tport->tp_write_urb_in_use = 1;
@@ -1380,7 +1379,13 @@ static void ti_send(struct ti_port *tport)
/* more room in the buffer for new writes, wakeup */
if (tty)
tty_wakeup(tty);
+ tty_kref_put(tty);
wake_up_interruptible(&tport->tp_write_wait);
+ return;
+unlock:
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
+ tty_kref_put(tty);
+ return;
}
@@ -1464,20 +1469,16 @@ static int ti_get_serial_info(struct ti_port *tport,
}
-static int ti_set_serial_info(struct ti_port *tport,
+static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
struct serial_struct __user *new_arg)
{
- struct usb_serial_port *port = tport->tp_port;
struct serial_struct new_serial;
if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
return -EFAULT;
tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS;
- /* FIXME */
- if (port->port.tty)
- port->port.tty->low_latency =
- (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0;
tport->tp_closing_wait = new_serial.closing_wait;
return 0;
@@ -1510,7 +1511,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
tport->tp_msr = msr & TI_MSR_MASK;
/* handle CTS flow control */
- tty = tport->tp_port->port.tty;
+ tty = tty_port_tty_get(&tport->tp_port->port);
if (tty && C_CRTSCTS(tty)) {
if (msr & TI_MSR_CTS) {
tty->hw_stopped = 0;
@@ -1519,6 +1520,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
tty->hw_stopped = 1;
}
}
+ tty_kref_put(tty);
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 4f7f9e3ae0a..e7d4246027b 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -214,7 +214,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
/* set up our port structure making the tty driver
* remember our port object, and us it */
tty->driver_data = port;
- port->port.tty = tty;
+ tty_port_tty_set(&port->port, tty);
if (port->port.count == 1) {
@@ -246,7 +246,7 @@ bailout_module_put:
bailout_mutex_unlock:
port->port.count = 0;
tty->driver_data = NULL;
- port->port.tty = NULL;
+ tty_port_tty_set(&port->port, NULL);
mutex_unlock(&port->mutex);
bailout_kref_put:
usb_serial_put(serial);
@@ -276,10 +276,11 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
port->serial->type->close(tty, port, filp);
if (port->port.count == (port->console? 1 : 0)) {
- if (port->port.tty) {
- if (port->port.tty->driver_data)
- port->port.tty->driver_data = NULL;
- port->port.tty = NULL;
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ if (tty->driver_data)
+ tty->driver_data = NULL;
+ tty_port_tty_set(&port->port, NULL);
}
}
@@ -508,11 +509,12 @@ static void usb_serial_port_work(struct work_struct *work)
if (!port)
return;
- tty = port->port.tty;
+ tty = tty_port_tty_get(&port->port);
if (!tty)
return;
tty_wakeup(tty);
+ tty_kref_put(tty);
}
static void port_release(struct device *dev)
@@ -819,6 +821,7 @@ int usb_serial_probe(struct usb_interface *interface,
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
goto probe_error;
+ tty_port_init(&port->port);
port->serial = serial;
spin_lock_init(&port->lock);
mutex_init(&port->mutex);
@@ -1040,8 +1043,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port) {
- if (port->port.tty)
- tty_hangup(port->port.tty);
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
kill_traffic(port);
}
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index cf8924f9a2c..a6d1c75a1c8 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -499,7 +499,7 @@ static void visor_read_bulk_callback(struct urb *urb)
int status = urb->status;
struct tty_struct *tty;
int result;
- int available_room;
+ int available_room = 0;
dbg("%s - port %d", __func__, port->number);
@@ -512,13 +512,17 @@ static void visor_read_bulk_callback(struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
- tty = port->port.tty;
- if (tty && urb->actual_length) {
- available_room = tty_buffer_request_room(tty,
+ if (urb->actual_length) {
+ tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ available_room = tty_buffer_request_room(tty,
urb->actual_length);
- if (available_room) {
- tty_insert_flip_string(tty, data, available_room);
- tty_flip_buffer_push(tty);
+ if (available_room) {
+ tty_insert_flip_string(tty, data,
+ available_room);
+ tty_flip_buffer_push(tty);
+ }
+ tty_kref_put(tty);
}
spin_lock(&priv->lock);
priv->bytes_in += available_room;
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 3a9d14384a4..11c8b97a517 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -1481,7 +1481,7 @@ static void rx_data_softint(struct work_struct *work)
struct whiteheat_private *info =
container_of(work, struct whiteheat_private, rx_work);
struct usb_serial_port *port = info->port;
- struct tty_struct *tty = port->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->port);
struct whiteheat_urb_wrap *wrap;
struct urb *urb;
unsigned long flags;
@@ -1493,7 +1493,7 @@ static void rx_data_softint(struct work_struct *work)
spin_lock_irqsave(&info->lock, flags);
if (info->flags & THROTTLED) {
spin_unlock_irqrestore(&info->lock, flags);
- return;
+ goto out;
}
list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
@@ -1513,7 +1513,7 @@ static void rx_data_softint(struct work_struct *work)
spin_unlock_irqrestore(&info->lock, flags);
tty_flip_buffer_push(tty);
schedule_work(&info->rx_work);
- return;
+ goto out;
}
tty_insert_flip_string(tty, urb->transfer_buffer, len);
sent += len;
@@ -1536,6 +1536,8 @@ static void rx_data_softint(struct work_struct *work)
if (sent)
tty_flip_buffer_push(tty);
+out:
+ tty_kref_put(tty);
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d85a74c64b5..f79c2040758 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -673,7 +673,6 @@ config FB_VESA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select VIDEO_SELECT
help
This is the frame buffer device driver for generic VESA 2.0
compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -1578,7 +1577,6 @@ config FB_CYBLA
tristate "Cyberblade/i1 support"
depends on FB && PCI && X86_32 && !64BIT
select FB_CFB_IMAGEBLIT
- select VIDEO_SELECT
---help---
This driver is supposed to support the Trident Cyberblade/i1
graphics core integrated in the VIA VT8601A North Bridge,
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 385cba40ea8..06964af761c 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -111,6 +111,4 @@ module_exit(mbp_exit);
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,1");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro3,2");
-MODULE_ALIAS("svnAppleInc.:pnMacBookPro4,1");
+MODULE_DEVICE_TABLE(dmi, mbp_device_table);
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index e721644bad7..1e35ba6f18e 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -372,7 +372,7 @@ static int __devexit bw2_remove(struct of_device *op)
return 0;
}
-static struct of_device_id bw2_match[] = {
+static const struct of_device_id bw2_match[] = {
{
.name = "bwtwo",
},
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index b17e7467177..a2d1882791a 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -589,7 +589,7 @@ static int __devexit cg14_remove(struct of_device *op)
return 0;
}
-static struct of_device_id cg14_match[] = {
+static const struct of_device_id cg14_match[] = {
{
.name = "cgfourteen",
},
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 3aa7b6cb026..99f87fb61d0 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -456,7 +456,7 @@ static int __devexit cg3_remove(struct of_device *op)
return 0;
}
-static struct of_device_id cg3_match[] = {
+static const struct of_device_id cg3_match[] = {
{
.name = "cgthree",
},
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 2f64bb3bd25..940ec04f0f1 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -34,10 +34,11 @@ static int cg6_blank(int, struct fb_info *);
static void cg6_imageblit(struct fb_info *, const struct fb_image *);
static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
static int cg6_sync(struct fb_info *);
static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
-static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *);
/*
* Frame buffer operations
@@ -47,6 +48,7 @@ static struct fb_ops cg6_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = cg6_setcolreg,
.fb_blank = cg6_blank,
+ .fb_pan_display = cg6_pan_display,
.fb_fillrect = cg6_fillrect,
.fb_copyarea = cg6_copyarea,
.fb_imageblit = cg6_imageblit,
@@ -161,6 +163,7 @@ static struct fb_ops cg6_ops = {
#define CG6_THC_MISC_INT_ENAB (1 << 5)
#define CG6_THC_MISC_INT (1 << 4)
#define CG6_THC_MISC_INIT 0x9f
+#define CG6_THC_CURSOFF ((65536-32) | ((65536-32) << 16))
/* The contents are unknown */
struct cg6_tec {
@@ -280,6 +283,33 @@ static int cg6_sync(struct fb_info *info)
return 0;
}
+static void cg6_switch_from_graph(struct cg6_par *par)
+{
+ struct cg6_thc __iomem *thc = par->thc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ /* Hide the cursor. */
+ sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct cg6_par *par = (struct cg6_par *)info->par;
+
+ /* We just use this to catch switches out of
+ * graphics mode.
+ */
+ cg6_switch_from_graph(par);
+
+ if (var->xoffset || var->yoffset || var->vmode)
+ return -EINVAL;
+ return 0;
+}
+
/**
* cg6_fillrect - Draws a rectangle on the screen.
*
@@ -643,9 +673,13 @@ static void __devinit cg6_chip_init(struct fb_info *info)
struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_tec __iomem *tec = par->tec;
struct cg6_fbc __iomem *fbc = par->fbc;
+ struct cg6_thc __iomem *thc = par->thc;
u32 rev, conf, mode;
int i;
+ /* Hide the cursor. */
+ sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
/* Turn off stuff in the Transform Engine. */
sbus_writel(0, &tec->tec_matrix);
sbus_writel(0, &tec->tec_clip);
@@ -814,7 +848,7 @@ static int __devexit cg6_remove(struct of_device *op)
return 0;
}
-static struct of_device_id cg6_match[] = {
+static const struct of_device_id cg6_match[] = {
{
.name = "cgsix",
},
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 06f87b04f20..2f50a80b413 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -43,22 +43,6 @@ config VGACON_SOFT_SCROLLBACK_SIZE
buffer. Each 64KB will give you approximately 16 80x25
screenfuls of scrollback buffer
-config VIDEO_SELECT
- bool "Video mode selection support"
- depends on X86 && VGA_CONSOLE
- ---help---
- This enables support for text mode selection on kernel startup. If
- you want to take advantage of some high-resolution text mode your
- card's BIOS offers, but the traditional Linux utilities like
- SVGATextMode don't, you can say Y here and set the mode using the
- "vga=" option from your boot loader (lilo or loadlin) or set
- "vga=ask" which brings up a video mode menu on kernel startup. (Try
- "man bootparam" or see the documentation of your boot loader about
- how to pass options to the kernel.)
-
- Read the file <file:Documentation/svga.txt> for more information
- about the Video mode selection support. If unsure, say N.
-
config MDA_CONSOLE
depends on !M68K && !PARISC && ISA
tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 7992b13ee68..9dbb9646081 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -1042,7 +1042,7 @@ static int __devexit ffb_remove(struct of_device *op)
return 0;
}
-static struct of_device_id ffb_match[] = {
+static const struct of_device_id ffb_match[] = {
{
.name = "SUNW,ffb",
},
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 13fea61d6ae..7c7e8c2da9d 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -33,6 +33,7 @@ static int leo_blank(int, struct fb_info *);
static int leo_mmap(struct fb_info *, struct vm_area_struct *);
static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
+static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
/*
* Frame buffer operations
@@ -42,6 +43,7 @@ static struct fb_ops leo_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = leo_setcolreg,
.fb_blank = leo_blank,
+ .fb_pan_display = leo_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
@@ -206,6 +208,60 @@ static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
return;
}
+static void leo_switch_from_graph(struct fb_info *info)
+{
+ struct leo_par *par = (struct leo_par *) info->par;
+ struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
+ struct leo_cursor __iomem *cursor = par->cursor;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ par->extent = ((info->var.xres - 1) |
+ ((info->var.yres - 1) << 16));
+
+ sbus_writel(0xffffffff, &ss->wid);
+ sbus_writel(0xffff, &ss->wmask);
+ sbus_writel(0, &ss->vclipmin);
+ sbus_writel(par->extent, &ss->vclipmax);
+ sbus_writel(0, &ss->fg);
+ sbus_writel(0xff000000, &ss->planemask);
+ sbus_writel(0x310850, &ss->rop);
+ sbus_writel(0, &ss->widclip);
+ sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
+ &par->lc_ss0_usr->extent);
+ sbus_writel(4, &par->lc_ss0_usr->addrspace);
+ sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
+ sbus_writel(0, &par->lc_ss0_usr->fontt);
+ do {
+ val = sbus_readl(&par->lc_ss0_usr->csr);
+ } while (val & 0x20000000);
+
+ /* setup screen buffer for cfb_* functions */
+ sbus_writel(1, &ss->wid);
+ sbus_writel(0x00ffffff, &ss->planemask);
+ sbus_writel(0x310b90, &ss->rop);
+ sbus_writel(0, &par->lc_ss0_usr->addrspace);
+
+ /* hide cursor */
+ sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc);
+
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ /* We just use this to catch switches out of
+ * graphics mode.
+ */
+ leo_switch_from_graph(info);
+
+ if (var->xoffset || var->yoffset || var->vmode)
+ return -EINVAL;
+ return 0;
+}
+
/**
* leo_setcolreg - Optional function. Sets a color register.
* @regno: boolean, 0 copy local, 1 get_user() function
@@ -454,44 +510,6 @@ static void leo_init_wids(struct fb_info *info)
leo_wid_put(info, &wl);
}
-static void leo_switch_from_graph(struct fb_info *info)
-{
- struct leo_par *par = (struct leo_par *) info->par;
- struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
- unsigned long flags;
- u32 val;
-
- spin_lock_irqsave(&par->lock, flags);
-
- par->extent = ((info->var.xres - 1) |
- ((info->var.yres - 1) << 16));
-
- sbus_writel(0xffffffff, &ss->wid);
- sbus_writel(0xffff, &ss->wmask);
- sbus_writel(0, &ss->vclipmin);
- sbus_writel(par->extent, &ss->vclipmax);
- sbus_writel(0, &ss->fg);
- sbus_writel(0xff000000, &ss->planemask);
- sbus_writel(0x310850, &ss->rop);
- sbus_writel(0, &ss->widclip);
- sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
- &par->lc_ss0_usr->extent);
- sbus_writel(4, &par->lc_ss0_usr->addrspace);
- sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
- sbus_writel(0, &par->lc_ss0_usr->fontt);
- do {
- val = sbus_readl(&par->lc_ss0_usr->csr);
- } while (val & 0x20000000);
-
- /* setup screen buffer for cfb_* functions */
- sbus_writel(1, &ss->wid);
- sbus_writel(0x00ffffff, &ss->planemask);
- sbus_writel(0x310b90, &ss->rop);
- sbus_writel(0, &par->lc_ss0_usr->addrspace);
-
- spin_unlock_irqrestore(&par->lock, flags);
-}
-
static void leo_init_hw(struct fb_info *info)
{
struct leo_par *par = (struct leo_par *) info->par;
@@ -641,7 +659,7 @@ static int __devexit leo_remove(struct of_device *op)
return 0;
}
-static struct of_device_id leo_match[] = {
+static const struct of_device_id leo_match[] = {
{
.name = "SUNW,leo",
},
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 9e903454ffc..7000f2cd585 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -349,7 +349,7 @@ static int __devexit p9100_remove(struct of_device *op)
return 0;
}
-static struct of_device_id p9100_match[] = {
+static const struct of_device_id p9100_match[] = {
{
.name = "p9100",
},
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 2a03f78bbb0..643afbfe827 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -505,7 +505,7 @@ static int __devexit tcx_remove(struct of_device *op)
return 0;
}
-static struct of_device_id tcx_match[] = {
+static const struct of_device_id tcx_match[] = {
{
.name = "SUNW,tcx",
},
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 47ed39b52f9..a463b3dd837 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -680,11 +680,11 @@ static struct xenbus_driver xenfb = {
static int __init xenfb_init(void)
{
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
/* Nothing to do if running in dom0. */
- if (is_initial_xendomain())
+ if (xen_initial_domain())
return -ENODEV;
return xenbus_register_frontend(&xenfb);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index c5103671670..1a22fe782a2 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -66,6 +66,13 @@ config AT91RM9200_WATCHDOG
Watchdog timer embedded into AT91RM9200 chips. This will reboot your
system when the timeout is reached.
+config AT91SAM9X_WATCHDOG
+ tristate "AT91SAM9X watchdog"
+ depends on WATCHDOG && (ARCH_AT91SAM9260 || ARCH_AT91SAM9261)
+ help
+ Watchdog timer embedded into AT91SAM9X chips. This will reboot your
+ system when the timeout is reached.
+
config 21285_WATCHDOG
tristate "DC21285 watchdog"
depends on FOOTBRIDGE
@@ -217,6 +224,15 @@ config DAVINCI_WATCHDOG
NOTE: once enabled, this timer cannot be disabled.
Say N if you are unsure.
+config ORION5X_WATCHDOG
+ tristate "Orion5x watchdog"
+ depends on ARCH_ORION5X
+ help
+ Say Y here if to include support for the watchdog timer
+ in the Orion5x ARM SoCs.
+ To compile this driver as a module, choose M here: the
+ module will be called orion5x_wdt.
+
# ARM26 Architecture
# AVR32 Architecture
@@ -416,6 +432,18 @@ config IT8712F_WDT
To compile this driver as a module, choose M here: the
module will be called it8712f_wdt.
+config IT87_WDT
+ tristate "IT87 Watchdog Timer"
+ depends on X86 && EXPERIMENTAL
+ ---help---
+ This is the driver for the hardware watchdog on the ITE IT8716,
+ IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog
+ simply watches your kernel to make sure it doesn't freeze, and if
+ it does, it reboots your computer after a certain amount of time.
+
+ To compile this driver as a module, choose M here: the module will
+ be called it87_wdt.
+
config HP_WATCHDOG
tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
depends on X86
@@ -573,6 +601,21 @@ config W83697HF_WDT
Most people will say N.
+config W83697UG_WDT
+ tristate "W83697UG/W83697UF Watchdog Timer"
+ depends on X86
+ ---help---
+ This is the driver for the hardware watchdog on the W83697UG/UF
+ chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
+ This watchdog simply watches your kernel to make sure it doesn't
+ freeze, and if it does, it reboots your computer after a certain
+ amount of time.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w83697ug_wdt.
+
+ Most people will say N.
+
config W83877F_WDT
tristate "W83877F (EMACS) Watchdog Timer"
depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index e0ef123fbde..e352bbb7630 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
+obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
@@ -39,6 +40,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
# ARM26 Architecture
@@ -71,6 +73,7 @@ ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
endif
obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
+obj-$(CONFIG_IT87_WDT) += it87_wdt.o
obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
@@ -83,6 +86,7 @@ obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
+obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
@@ -123,6 +127,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
# SPARC64 Architecture
+obj-$(CONFIG_WATCHDOG_RIO) += riowd.o
+obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
+
# XTENSA Architecture
# Architecture Independant
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
new file mode 100644
index 00000000000..b4babfc3158
--- /dev/null
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -0,0 +1,328 @@
+/*
+ * Watchdog driver for Atmel AT91SAM9x processors.
+ *
+ * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The Watchdog Timer Mode Register can be only written to once. If the
+ * timeout need to be set from Linux, be sure that the bootstrap or the
+ * bootloader doesn't write to this register.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+
+#include <asm/arch/at91_wdt.h>
+
+#define DRV_NAME "AT91SAM9 Watchdog"
+
+/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
+ * use this to convert a watchdog
+ * value from/to milliseconds.
+ */
+#define ms_to_ticks(t) (((t << 8) / 1000) - 1)
+#define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
+
+/* Hardware timeout in seconds */
+#define WDT_HW_TIMEOUT 2
+
+/* Timer heartbeat (500ms) */
+#define WDT_TIMEOUT (HZ/2)
+
+/* User land timeout */
+#define WDT_HEARTBEAT 15
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
+ "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+ "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static void at91_ping(unsigned long data);
+
+static struct {
+ unsigned long next_heartbeat; /* the next_heartbeat for the timer */
+ unsigned long open;
+ char expect_close;
+ struct timer_list timer; /* The timer that pings the watchdog */
+} at91wdt_private;
+
+/* ......................................................................... */
+
+
+/*
+ * Reload the watchdog timer. (ie, pat the watchdog)
+ */
+static inline void at91_wdt_reset(void)
+{
+ at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+}
+
+/*
+ * Timer tick
+ */
+static void at91_ping(unsigned long data)
+{
+ if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
+ (!nowayout && !at91wdt_private.open)) {
+ at91_wdt_reset();
+ mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+ } else
+ printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &at91wdt_private.open))
+ return -EBUSY;
+
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+ mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+ return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+ clear_bit(0, &at91wdt_private.open);
+
+ /* stop internal ping */
+ if (!at91wdt_private.expect_close)
+ del_timer(&at91wdt_private.timer);
+
+ at91wdt_private.expect_close = 0;
+ return 0;
+}
+
+/*
+ * Set the watchdog time interval in 1/256Hz (write-once)
+ * Counter is 12 bit.
+ */
+static int at91_wdt_settimeout(unsigned int timeout)
+{
+ unsigned int reg;
+ unsigned int mr;
+
+ /* Check if disabled */
+ mr = at91_sys_read(AT91_WDT_MR);
+ if (mr & AT91_WDT_WDDIS) {
+ printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+ return -EIO;
+ }
+
+ /*
+ * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
+ *
+ * Since WDV is a 12-bit counter, the maximum period is
+ * 4096 / 256 = 16 seconds.
+ */
+ reg = AT91_WDT_WDRSTEN /* causes watchdog reset */
+ /* | AT91_WDT_WDRPROC causes processor reset only */
+ | AT91_WDT_WDDBGHLT /* disabled in debug mode */
+ | AT91_WDT_WDD /* restart at any time */
+ | (timeout & AT91_WDT_WDV); /* timer value */
+ at91_sys_write(AT91_WDT_MR, reg);
+
+ return 0;
+}
+
+static const struct watchdog_info at91_wdt_info = {
+ .identity = DRV_NAME,
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static long at91_wdt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_value;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &at91_wdt_info,
+ sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_KEEPALIVE:
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_value, p))
+ return -EFAULT;
+
+ heartbeat = new_value;
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+ return put_user(new_value, p); /* return current value */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+ }
+ return -ENOTTY;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t *ppos)
+{
+ if (!len)
+ return 0;
+
+ /* Scan for magic character */
+ if (!nowayout) {
+ size_t i;
+
+ at91wdt_private.expect_close = 0;
+
+ for (i = 0; i < len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V') {
+ at91wdt_private.expect_close = 42;
+ break;
+ }
+ }
+ }
+
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+ return len;
+}
+
+/* ......................................................................... */
+
+static const struct file_operations at91wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .unlocked_ioctl = at91_wdt_ioctl,
+ .open = at91_wdt_open,
+ .release = at91_wdt_close,
+ .write = at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &at91wdt_fops,
+};
+
+static int __init at91wdt_probe(struct platform_device *pdev)
+{
+ int res;
+
+ if (at91wdt_miscdev.parent)
+ return -EBUSY;
+ at91wdt_miscdev.parent = &pdev->dev;
+
+ /* Set watchdog */
+ res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
+ if (res)
+ return res;
+
+ res = misc_register(&at91wdt_miscdev);
+ if (res)
+ return res;
+
+ at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+ setup_timer(&at91wdt_private.timer, at91_ping, 0);
+ mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+ printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+ heartbeat, nowayout);
+
+ return 0;
+}
+
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+ int res;
+
+ res = misc_deregister(&at91wdt_miscdev);
+ if (!res)
+ at91wdt_miscdev.parent = NULL;
+
+ return res;
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#else
+#define at91wdt_suspend NULL
+#define at91wdt_resume NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+ .remove = __exit_p(at91wdt_remove),
+ .suspend = at91wdt_suspend,
+ .resume = at91wdt_resume,
+ .driver = {
+ .name = "at91_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91sam_wdt_init(void)
+{
+ return platform_driver_probe(&at91wdt_driver, at91wdt_probe);
+}
+
+static void __exit at91sam_wdt_exit(void)
+{
+ platform_driver_unregister(&at91wdt_driver);
+}
+
+module_init(at91sam_wdt_init);
+module_exit(at91sam_wdt_exit);
+
+MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
new file mode 100644
index 00000000000..084dfe9cecf
--- /dev/null
+++ b/drivers/watchdog/cpwd.c
@@ -0,0 +1,695 @@
+/* cpwd.c - driver implementation for hardware watchdog
+ * timers found on Sun Microsystems CP1400 and CP1500 boards.
+ *
+ * This device supports both the generic Linux watchdog
+ * interface and Solaris-compatible ioctls as best it is
+ * able.
+ *
+ * NOTE: CP1400 systems appear to have a defective intr_mask
+ * register on the PLD, preventing the disabling of
+ * timer interrupts. We use a timer to periodically
+ * reset 'stopped' watchdogs on affected platforms.
+ *
+ * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/smp_lock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include <asm/watchdog.h>
+
+#define DRIVER_NAME "cpwd"
+#define PFX DRIVER_NAME ": "
+
+#define WD_OBPNAME "watchdog"
+#define WD_BADMODEL "SUNW,501-5336"
+#define WD_BTIMEOUT (jiffies + (HZ * 1000))
+#define WD_BLIMIT 0xFFFF
+
+#define WD0_MINOR 212
+#define WD1_MINOR 213
+#define WD2_MINOR 214
+
+/* Internal driver definitions. */
+#define WD0_ID 0
+#define WD1_ID 1
+#define WD2_ID 2
+#define WD_NUMDEVS 3
+
+#define WD_INTR_OFF 0
+#define WD_INTR_ON 1
+
+#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */
+#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */
+#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */
+
+/* Register value definitions
+ */
+#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */
+#define WD1_INTR_MASK 0x02
+#define WD2_INTR_MASK 0x04
+
+#define WD_S_RUNNING 0x01 /* Watchdog device status running */
+#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */
+
+struct cpwd {
+ void __iomem *regs;
+ spinlock_t lock;
+
+ unsigned int irq;
+
+ unsigned long timeout;
+ bool enabled;
+ bool reboot;
+ bool broken;
+ bool initialized;
+
+ struct {
+ struct miscdevice misc;
+ void __iomem *regs;
+ u8 intr_mask;
+ u8 runstatus;
+ u16 timeout;
+ } devs[WD_NUMDEVS];
+};
+
+static struct cpwd *cpwd_device;
+
+/* Sun uses Altera PLD EPF8820ATC144-4
+ * providing three hardware watchdogs:
+ *
+ * 1) RIC - sends an interrupt when triggered
+ * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU
+ * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
+ *
+ *** Timer register block definition (struct wd_timer_regblk)
+ *
+ * dcntr and limit registers (halfword access):
+ * -------------------
+ * | 15 | ...| 1 | 0 |
+ * -------------------
+ * |- counter val -|
+ * -------------------
+ * dcntr - Current 16-bit downcounter value.
+ * When downcounter reaches '0' watchdog expires.
+ * Reading this register resets downcounter with 'limit' value.
+ * limit - 16-bit countdown value in 1/10th second increments.
+ * Writing this register begins countdown with input value.
+ * Reading from this register does not affect counter.
+ * NOTES: After watchdog reset, dcntr and limit contain '1'
+ *
+ * status register (byte access):
+ * ---------------------------
+ * | 7 | ... | 2 | 1 | 0 |
+ * --------------+------------
+ * |- UNUSED -| EXP | RUN |
+ * ---------------------------
+ * status- Bit 0 - Watchdog is running
+ * Bit 1 - Watchdog has expired
+ *
+ *** PLD register block definition (struct wd_pld_regblk)
+ *
+ * intr_mask register (byte access):
+ * ---------------------------------
+ * | 7 | ... | 3 | 2 | 1 | 0 |
+ * +-------------+------------------
+ * |- UNUSED -| WD3 | WD2 | WD1 |
+ * ---------------------------------
+ * WD3 - 1 == Interrupt disabled for watchdog 3
+ * WD2 - 1 == Interrupt disabled for watchdog 2
+ * WD1 - 1 == Interrupt disabled for watchdog 1
+ *
+ * pld_status register (byte access):
+ * UNKNOWN, MAGICAL MYSTERY REGISTER
+ *
+ */
+#define WD_TIMER_REGSZ 16
+#define WD0_OFF 0
+#define WD1_OFF (WD_TIMER_REGSZ * 1)
+#define WD2_OFF (WD_TIMER_REGSZ * 2)
+#define PLD_OFF (WD_TIMER_REGSZ * 3)
+
+#define WD_DCNTR 0x00
+#define WD_LIMIT 0x04
+#define WD_STATUS 0x08
+
+#define PLD_IMASK (PLD_OFF + 0x00)
+#define PLD_STATUS (PLD_OFF + 0x04)
+
+static struct timer_list cpwd_timer;
+
+static int wd0_timeout = 0;
+static int wd1_timeout = 0;
+static int wd2_timeout = 0;
+
+module_param (wd0_timeout, int, 0);
+MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
+module_param (wd1_timeout, int, 0);
+MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
+module_param (wd2_timeout, int, 0);
+MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
+
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("watchdog");
+
+static void cpwd_writew(u16 val, void __iomem *addr)
+{
+ writew(cpu_to_le16(val), addr);
+}
+static u16 cpwd_readw(void __iomem *addr)
+{
+ u16 val = readw(addr);
+
+ return le16_to_cpu(val);
+}
+
+static void cpwd_writeb(u8 val, void __iomem *addr)
+{
+ writeb(val, addr);
+}
+
+static u8 cpwd_readb(void __iomem *addr)
+{
+ return readb(addr);
+}
+
+/* Enable or disable watchdog interrupts
+ * Because of the CP1400 defect this should only be
+ * called during initialzation or by wd_[start|stop]timer()
+ *
+ * index - sub-device index, or -1 for 'all'
+ * enable - non-zero to enable interrupts, zero to disable
+ */
+static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
+{
+ unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK);
+ unsigned char setregs =
+ (index == -1) ?
+ (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) :
+ (p->devs[index].intr_mask);
+
+ if (enable == WD_INTR_ON)
+ curregs &= ~setregs;
+ else
+ curregs |= setregs;
+
+ cpwd_writeb(curregs, p->regs + PLD_IMASK);
+}
+
+/* Restarts timer with maximum limit value and
+ * does not unset 'brokenstop' value.
+ */
+static void cpwd_resetbrokentimer(struct cpwd *p, int index)
+{
+ cpwd_toggleintr(p, index, WD_INTR_ON);
+ cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT);
+}
+
+/* Timer method called to reset stopped watchdogs--
+ * because of the PLD bug on CP1400, we cannot mask
+ * interrupts within the PLD so me must continually
+ * reset the timers ad infinitum.
+ */
+static void cpwd_brokentimer(unsigned long data)
+{
+ struct cpwd *p = (struct cpwd *) data;
+ int id, tripped = 0;
+
+ /* kill a running timer instance, in case we
+ * were called directly instead of by kernel timer
+ */
+ if (timer_pending(&cpwd_timer))
+ del_timer(&cpwd_timer);
+
+ for (id = 0; id < WD_NUMDEVS; id++) {
+ if (p->devs[id].runstatus & WD_STAT_BSTOP) {
+ ++tripped;
+ cpwd_resetbrokentimer(p, id);
+ }
+ }
+
+ if (tripped) {
+ /* there is at least one timer brokenstopped-- reschedule */
+ cpwd_timer.expires = WD_BTIMEOUT;
+ add_timer(&cpwd_timer);
+ }
+}
+
+/* Reset countdown timer with 'limit' value and continue countdown.
+ * This will not start a stopped timer.
+ */
+static void cpwd_pingtimer(struct cpwd *p, int index)
+{
+ if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING)
+ cpwd_readw(p->devs[index].regs + WD_DCNTR);
+}
+
+/* Stop a running watchdog timer-- the timer actually keeps
+ * running, but the interrupt is masked so that no action is
+ * taken upon expiration.
+ */
+static void cpwd_stoptimer(struct cpwd *p, int index)
+{
+ if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) {
+ cpwd_toggleintr(p, index, WD_INTR_OFF);
+
+ if (p->broken) {
+ p->devs[index].runstatus |= WD_STAT_BSTOP;
+ cpwd_brokentimer((unsigned long) p);
+ }
+ }
+}
+
+/* Start a watchdog timer with the specified limit value
+ * If the watchdog is running, it will be restarted with
+ * the provided limit value.
+ *
+ * This function will enable interrupts on the specified
+ * watchdog.
+ */
+static void cpwd_starttimer(struct cpwd *p, int index)
+{
+ if (p->broken)
+ p->devs[index].runstatus &= ~WD_STAT_BSTOP;
+
+ p->devs[index].runstatus &= ~WD_STAT_SVCD;
+
+ cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT);
+ cpwd_toggleintr(p, index, WD_INTR_ON);
+}
+
+static int cpwd_getstatus(struct cpwd *p, int index)
+{
+ unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS);
+ unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK);
+ unsigned char ret = WD_STOPPED;
+
+ /* determine STOPPED */
+ if (!stat)
+ return ret;
+
+ /* determine EXPIRED vs FREERUN vs RUNNING */
+ else if (WD_S_EXPIRED & stat) {
+ ret = WD_EXPIRED;
+ } else if(WD_S_RUNNING & stat) {
+ if (intr & p->devs[index].intr_mask) {
+ ret = WD_FREERUN;
+ } else {
+ /* Fudge WD_EXPIRED status for defective CP1400--
+ * IF timer is running
+ * AND brokenstop is set
+ * AND an interrupt has been serviced
+ * we are WD_EXPIRED.
+ *
+ * IF timer is running
+ * AND brokenstop is set
+ * AND no interrupt has been serviced
+ * we are WD_FREERUN.
+ */
+ if (p->broken &&
+ (p->devs[index].runstatus & WD_STAT_BSTOP)) {
+ if (p->devs[index].runstatus & WD_STAT_SVCD) {
+ ret = WD_EXPIRED;
+ } else {
+ /* we could as well pretend we are expired */
+ ret = WD_FREERUN;
+ }
+ } else {
+ ret = WD_RUNNING;
+ }
+ }
+ }
+
+ /* determine SERVICED */
+ if (p->devs[index].runstatus & WD_STAT_SVCD)
+ ret |= WD_SERVICED;
+
+ return(ret);
+}
+
+static irqreturn_t cpwd_interrupt(int irq, void *dev_id)
+{
+ struct cpwd *p = dev_id;
+
+ /* Only WD0 will interrupt-- others are NMI and we won't
+ * see them here....
+ */
+ spin_lock_irq(&p->lock);
+
+ cpwd_stoptimer(p, WD0_ID);
+ p->devs[WD0_ID].runstatus |= WD_STAT_SVCD;
+
+ spin_unlock_irq(&p->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int cpwd_open(struct inode *inode, struct file *f)
+{
+ struct cpwd *p = cpwd_device;
+
+ lock_kernel();
+ switch(iminor(inode)) {
+ case WD0_MINOR:
+ case WD1_MINOR:
+ case WD2_MINOR:
+ break;
+
+ default:
+ unlock_kernel();
+ return -ENODEV;
+ }
+
+ /* Register IRQ on first open of device */
+ if (!p->initialized) {
+ if (request_irq(p->irq, &cpwd_interrupt,
+ IRQF_SHARED, DRIVER_NAME, p)) {
+ printk(KERN_ERR PFX "Cannot register IRQ %d\n",
+ p->irq);
+ unlock_kernel();
+ return -EBUSY;
+ }
+ p->initialized = true;
+ }
+
+ unlock_kernel();
+
+ return nonseekable_open(inode, f);
+}
+
+static int cpwd_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int cpwd_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ static struct watchdog_info info = {
+ .options = WDIOF_SETTIMEOUT,
+ .firmware_version = 1,
+ .identity = DRIVER_NAME,
+ };
+ void __user *argp = (void __user *)arg;
+ int index = iminor(inode) - WD0_MINOR;
+ struct cpwd *p = cpwd_device;
+ int setopt = 0;
+
+ switch (cmd) {
+ /* Generic Linux IOCTLs */
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &info, sizeof(struct watchdog_info)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ if (put_user(0, (int __user *)argp))
+ return -EFAULT;
+ break;
+
+ case WDIOC_KEEPALIVE:
+ cpwd_pingtimer(p, index);
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (copy_from_user(&setopt, argp, sizeof(unsigned int)))
+ return -EFAULT;
+
+ if (setopt & WDIOS_DISABLECARD) {
+ if (p->enabled)
+ return -EINVAL;
+ cpwd_stoptimer(p, index);
+ } else if (setopt & WDIOS_ENABLECARD) {
+ cpwd_starttimer(p, index);
+ } else {
+ return -EINVAL;
+ }
+ break;
+
+ /* Solaris-compatible IOCTLs */
+ case WIOCGSTAT:
+ setopt = cpwd_getstatus(p, index);
+ if (copy_to_user(argp, &setopt, sizeof(unsigned int)))
+ return -EFAULT;
+ break;
+
+ case WIOCSTART:
+ cpwd_starttimer(p, index);
+ break;
+
+ case WIOCSTOP:
+ if (p->enabled)
+ return(-EINVAL);
+
+ cpwd_stoptimer(p, index);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static long cpwd_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rval = -ENOIOCTLCMD;
+
+ switch (cmd) {
+ /* solaris ioctls are specific to this driver */
+ case WIOCSTART:
+ case WIOCSTOP:
+ case WIOCGSTAT:
+ lock_kernel();
+ rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+ unlock_kernel();
+ break;
+
+ /* everything else is handled by the generic compat layer */
+ default:
+ break;
+ }
+
+ return rval;
+}
+
+static ssize_t cpwd_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct cpwd *p = cpwd_device;
+ int index = iminor(inode);
+
+ if (count) {
+ cpwd_pingtimer(p, index);
+ return 1;
+ }
+
+ return 0;
+}
+
+static ssize_t cpwd_read(struct file * file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static const struct file_operations cpwd_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = cpwd_ioctl,
+ .compat_ioctl = cpwd_compat_ioctl,
+ .open = cpwd_open,
+ .write = cpwd_write,
+ .read = cpwd_read,
+ .release = cpwd_release,
+};
+
+static int __devinit cpwd_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *options;
+ const char *str_prop;
+ const void *prop_val;
+ int i, err = -EINVAL;
+ struct cpwd *p;
+
+ if (cpwd_device)
+ return -EINVAL;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!p) {
+ printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n");
+ goto out;
+ }
+
+ p->irq = op->irqs[0];
+
+ spin_lock_init(&p->lock);
+
+ p->regs = of_ioremap(&op->resource[0], 0,
+ 4 * WD_TIMER_REGSZ, DRIVER_NAME);
+ if (!p->regs) {
+ printk(KERN_ERR PFX "Unable to map registers.\n");
+ goto out_free;
+ }
+
+ options = of_find_node_by_path("/options");
+ err = -ENODEV;
+ if (!options) {
+ printk(KERN_ERR PFX "Unable to find /options node.\n");
+ goto out_iounmap;
+ }
+
+ prop_val = of_get_property(options, "watchdog-enable?", NULL);
+ p->enabled = (prop_val ? true : false);
+
+ prop_val = of_get_property(options, "watchdog-reboot?", NULL);
+ p->reboot = (prop_val ? true : false);
+
+ str_prop = of_get_property(options, "watchdog-timeout", NULL);
+ if (str_prop)
+ p->timeout = simple_strtoul(str_prop, NULL, 10);
+
+ /* CP1400s seem to have broken PLD implementations-- the
+ * interrupt_mask register cannot be written, so no timer
+ * interrupts can be masked within the PLD.
+ */
+ str_prop = of_get_property(op->node, "model", NULL);
+ p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));
+
+ if (!p->enabled)
+ cpwd_toggleintr(p, -1, WD_INTR_OFF);
+
+ for (i = 0; i < WD_NUMDEVS; i++) {
+ static const char *cpwd_names[] = { "RIC", "XIR", "POR" };
+ static int *parms[] = { &wd0_timeout,
+ &wd1_timeout,
+ &wd2_timeout };
+ struct miscdevice *mp = &p->devs[i].misc;
+
+ mp->minor = WD0_MINOR + i;
+ mp->name = cpwd_names[i];
+ mp->fops = &cpwd_fops;
+
+ p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ);
+ p->devs[i].intr_mask = (WD0_INTR_MASK << i);
+ p->devs[i].runstatus &= ~WD_STAT_BSTOP;
+ p->devs[i].runstatus |= WD_STAT_INIT;
+ p->devs[i].timeout = p->timeout;
+ if (*parms[i])
+ p->devs[i].timeout = *parms[i];
+
+ err = misc_register(&p->devs[i].misc);
+ if (err) {
+ printk(KERN_ERR "Could not register misc device for "
+ "dev %d\n", i);
+ goto out_unregister;
+ }
+ }
+
+ if (p->broken) {
+ init_timer(&cpwd_timer);
+ cpwd_timer.function = cpwd_brokentimer;
+ cpwd_timer.data = (unsigned long) p;
+ cpwd_timer.expires = WD_BTIMEOUT;
+
+ printk(KERN_INFO PFX "PLD defect workaround enabled for "
+ "model " WD_BADMODEL ".\n");
+ }
+
+ dev_set_drvdata(&op->dev, p);
+ cpwd_device = p;
+ err = 0;
+
+out:
+ return err;
+
+out_unregister:
+ for (i--; i >= 0; i--)
+ misc_deregister(&p->devs[i].misc);
+
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+
+out_free:
+ kfree(p);
+ goto out;
+}
+
+static int __devexit cpwd_remove(struct of_device *op)
+{
+ struct cpwd *p = dev_get_drvdata(&op->dev);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ misc_deregister(&p->devs[i].misc);
+
+ if (!p->enabled) {
+ cpwd_stoptimer(p, i);
+ if (p->devs[i].runstatus & WD_STAT_BSTOP)
+ cpwd_resetbrokentimer(p, i);
+ }
+ }
+
+ if (p->broken)
+ del_timer_sync(&cpwd_timer);
+
+ if (p->initialized)
+ free_irq(p->irq, p);
+
+ of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+ kfree(p);
+
+ cpwd_device = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id cpwd_match[] = {
+ {
+ .name = "watchdog",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cpwd_match);
+
+static struct of_platform_driver cpwd_driver = {
+ .name = DRIVER_NAME,
+ .match_table = cpwd_match,
+ .probe = cpwd_probe,
+ .remove = __devexit_p(cpwd_remove),
+};
+
+static int __init cpwd_init(void)
+{
+ return of_register_driver(&cpwd_driver, &of_bus_type);
+}
+
+static void __exit cpwd_exit(void)
+{
+ of_unregister_driver(&cpwd_driver);
+}
+
+module_init(cpwd_init);
+module_exit(cpwd_exit);
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
new file mode 100644
index 00000000000..afb8af397a9
--- /dev/null
+++ b/drivers/watchdog/it87_wdt.c
@@ -0,0 +1,725 @@
+/*
+ * Watchdog Timer Driver
+ * for ITE IT87xx Environment Control - Low Pin Count Input / Output
+ *
+ * (c) Copyright 2007 Oliver Schuster <olivers137@aol.com>
+ *
+ * Based on softdog.c by Alan Cox,
+ * 83977f_wdt.c by Jose Goncalves,
+ * it87.c by Chris Gauthron, Jean Delvare
+ *
+ * Data-sheets: Publicly available at the ITE website
+ * http://www.ite.com.tw/
+ *
+ * Support of the watchdog timers, which are available on
+ * IT8716, IT8718, IT8726 and IT8712 (J,K version).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_VERSION "1.12"
+#define WATCHDOG_NAME "IT87 WDT"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define WD_MAGIC 'V'
+
+/* Defaults for Module Parameter */
+#define DEFAULT_NOGAMEPORT 0
+#define DEFAULT_EXCLUSIVE 1
+#define DEFAULT_TIMEOUT 60
+#define DEFAULT_TESTMODE 0
+#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT
+
+/* IO Ports */
+#define REG 0x2e
+#define VAL 0x2f
+
+/* Logical device Numbers LDN */
+#define GPIO 0x07
+#define GAMEPORT 0x09
+#define CIR 0x0a
+
+/* Configuration Registers and Functions */
+#define LDNREG 0x07
+#define CHIPID 0x20
+#define CHIPREV 0x22
+#define ACTREG 0x30
+#define BASEREG 0x60
+
+/* Chip Id numbers */
+#define NO_DEV_ID 0xffff
+#define IT8705_ID 0x8705
+#define IT8712_ID 0x8712
+#define IT8716_ID 0x8716
+#define IT8718_ID 0x8718
+#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
+
+/* GPIO Configuration Registers LDN=0x07 */
+#define WDTCTRL 0x71
+#define WDTCFG 0x72
+#define WDTVALLSB 0x73
+#define WDTVALMSB 0x74
+
+/* GPIO Bits WDTCTRL */
+#define WDT_CIRINT 0x80
+#define WDT_MOUSEINT 0x40
+#define WDT_KYBINT 0x20
+#define WDT_GAMEPORT 0x10 /* not it8718 */
+#define WDT_FORCE 0x02
+#define WDT_ZERO 0x01
+
+/* GPIO Bits WDTCFG */
+#define WDT_TOV1 0x80
+#define WDT_KRST 0x40
+#define WDT_TOVE 0x20
+#define WDT_PWROK 0x10
+#define WDT_INT_MASK 0x0f
+
+/* CIR Configuration Register LDN=0x0a */
+#define CIR_ILS 0x70
+
+/* The default Base address is not always available, we use this */
+#define CIR_BASE 0x0208
+
+/* CIR Controller */
+#define CIR_DR(b) (b)
+#define CIR_IER(b) (b + 1)
+#define CIR_RCR(b) (b + 2)
+#define CIR_TCR1(b) (b + 3)
+#define CIR_TCR2(b) (b + 4)
+#define CIR_TSR(b) (b + 5)
+#define CIR_RSR(b) (b + 6)
+#define CIR_BDLR(b) (b + 5)
+#define CIR_BDHR(b) (b + 6)
+#define CIR_IIR(b) (b + 7)
+
+/* Default Base address of Game port */
+#define GP_BASE_DEFAULT 0x0201
+
+/* wdt_status */
+#define WDTS_TIMER_RUN 0
+#define WDTS_DEV_OPEN 1
+#define WDTS_KEEPALIVE 2
+#define WDTS_LOCKED 3
+#define WDTS_USE_GP 4
+#define WDTS_EXPECTED 5
+
+static unsigned int base, gpact, ciract;
+static unsigned long wdt_status;
+static DEFINE_SPINLOCK(spinlock);
+
+static int nogameport = DEFAULT_NOGAMEPORT;
+static int exclusive = DEFAULT_EXCLUSIVE;
+static int timeout = DEFAULT_TIMEOUT;
+static int testmode = DEFAULT_TESTMODE;
+static int nowayout = DEFAULT_NOWAYOUT;
+
+module_param(nogameport, int, 0);
+MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
+ __MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(exclusive, int, 0);
+MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
+ __MODULE_STRING(DEFAULT_EXCLUSIVE));
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
+ __MODULE_STRING(DEFAULT_TIMEOUT));
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
+ __MODULE_STRING(DEFAULT_TESTMODE));
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT));
+
+/* Superio Chip */
+
+static inline void superio_enter(void)
+{
+ outb(0x87, REG);
+ outb(0x01, REG);
+ outb(0x55, REG);
+ outb(0x55, REG);
+}
+
+static inline void superio_exit(void)
+{
+ outb(0x02, REG);
+ outb(0x02, VAL);
+}
+
+static inline void superio_select(int ldn)
+{
+ outb(LDNREG, REG);
+ outb(ldn, VAL);
+}
+
+static inline int superio_inb(int reg)
+{
+ outb(reg, REG);
+ return inb(VAL);
+}
+
+static inline void superio_outb(int val, int reg)
+{
+ outb(reg, REG);
+ outb(val, VAL);
+}
+
+static inline int superio_inw(int reg)
+{
+ int val;
+ outb(reg++, REG);
+ val = inb(VAL) << 8;
+ outb(reg, REG);
+ val |= inb(VAL);
+ return val;
+}
+
+static inline void superio_outw(int val, int reg)
+{
+ outb(reg++, REG);
+ outb(val >> 8, VAL);
+ outb(reg, REG);
+ outb(val, VAL);
+}
+
+/* watchdog timer handling */
+
+static void wdt_keepalive(void)
+{
+ if (test_bit(WDTS_USE_GP, &wdt_status))
+ inb(base);
+ else
+ /* The timer reloads with around 5 msec delay */
+ outb(0x55, CIR_DR(base));
+ set_bit(WDTS_KEEPALIVE, &wdt_status);
+}
+
+static void wdt_start(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(GPIO);
+ if (test_bit(WDTS_USE_GP, &wdt_status))
+ superio_outb(WDT_GAMEPORT, WDTCTRL);
+ else
+ superio_outb(WDT_CIRINT, WDTCTRL);
+ if (!testmode)
+ superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG);
+ else
+ superio_outb(WDT_TOV1, WDTCFG);
+ superio_outb(timeout>>8, WDTVALMSB);
+ superio_outb(timeout, WDTVALLSB);
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+}
+
+static void wdt_stop(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(GPIO);
+ superio_outb(0x00, WDTCTRL);
+ superio_outb(WDT_TOV1, WDTCFG);
+ superio_outb(0x00, WDTVALMSB);
+ superio_outb(0x00, WDTVALLSB);
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+}
+
+/**
+ * wdt_set_timeout - set a new timeout value with watchdog ioctl
+ * @t: timeout value in seconds
+ *
+ * The hardware device has a 16 bit watchdog timer, thus the
+ * timeout time ranges between 1 and 65535 seconds.
+ *
+ * Used within WDIOC_SETTIMEOUT watchdog device ioctl.
+ */
+
+static int wdt_set_timeout(int t)
+{
+ unsigned long flags;
+
+ if (t < 1 || t > 65535)
+ return -EINVAL;
+
+ timeout = t;
+
+ spin_lock_irqsave(&spinlock, flags);
+ if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+ superio_enter();
+
+ superio_select(GPIO);
+ superio_outb(t>>8, WDTVALMSB);
+ superio_outb(t, WDTVALLSB);
+
+ superio_exit();
+ }
+ spin_unlock_irqrestore(&spinlock, flags);
+ return 0;
+}
+
+/**
+ * wdt_get_status - determines the status supported by watchdog ioctl
+ * @status: status returned to user space
+ *
+ * The status bit of the device does not allow to distinguish
+ * between a regular system reset and a watchdog forced reset.
+ * But, in test mode it is useful, so it is supported through
+ * WDIOC_GETSTATUS watchdog ioctl. Additionally the driver
+ * reports the keepalive signal and the acception of the magic.
+ *
+ * Used within WDIOC_GETSTATUS watchdog device ioctl.
+ */
+
+static int wdt_get_status(int *status)
+{
+ unsigned long flags;
+
+ *status = 0;
+ if (testmode) {
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(GPIO);
+ if (superio_inb(WDTCTRL) & WDT_ZERO) {
+ superio_outb(0x00, WDTCTRL);
+ clear_bit(WDTS_TIMER_RUN, &wdt_status);
+ *status |= WDIOF_CARDRESET;
+ }
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+ if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
+ *status |= WDIOF_KEEPALIVEPING;
+ if (test_bit(WDTS_EXPECTED, &wdt_status))
+ *status |= WDIOF_MAGICCLOSE;
+ return 0;
+}
+
+/* /dev/watchdog handling */
+
+/**
+ * wdt_open - watchdog file_operations .open
+ * @inode: inode of the device
+ * @file: file handle to the device
+ *
+ * The watchdog timer starts by opening the device.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+ if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
+ return -EBUSY;
+ if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+ if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
+ __module_get(THIS_MODULE);
+ wdt_start();
+ }
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * wdt_release - watchdog file_operations .release
+ * @inode: inode of the device
+ * @file: file handle to the device
+ *
+ * Closing the watchdog device either stops the watchdog timer
+ * or in the case, that nowayout is set or the magic character
+ * wasn't written, a critical warning about an running watchdog
+ * timer is given.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+ if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
+ wdt_stop();
+ clear_bit(WDTS_TIMER_RUN, &wdt_status);
+ } else {
+ wdt_keepalive();
+ printk(KERN_CRIT PFX
+ "unexpected close, not stopping watchdog!\n");
+ }
+ }
+ clear_bit(WDTS_DEV_OPEN, &wdt_status);
+ return 0;
+}
+
+/**
+ * wdt_write - watchdog file_operations .write
+ * @file: file handle to the watchdog
+ * @buf: buffer to write
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we don't define content meaning.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ clear_bit(WDTS_EXPECTED, &wdt_status);
+ wdt_keepalive();
+ }
+ if (!nowayout) {
+ size_t ofs;
+
+ /* note: just in case someone wrote the magic character long ago */
+ for (ofs = 0; ofs != count; ofs++) {
+ char c;
+ if (get_user(c, buf + ofs))
+ return -EFAULT;
+ if (c == WD_MAGIC)
+ set_bit(WDTS_EXPECTED, &wdt_status);
+ }
+ }
+ return count;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = WATCHDOG_NAME,
+};
+
+/**
+ * wdt_ioctl - watchdog file_operations .unlocked_ioctl
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features.
+ *
+ * Used within the file operation of the watchdog device.
+ */
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int rc = 0, status, new_options, new_timeout;
+ union {
+ struct watchdog_info __user *ident;
+ int __user *i;
+ } uarg;
+
+ uarg.i = (int __user *)arg;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(uarg.ident,
+ &ident, sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ wdt_get_status(&status);
+ return put_user(status, uarg.i);
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, uarg.i);
+
+ case WDIOC_KEEPALIVE:
+ wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(new_options, uarg.i))
+ return -EFAULT;
+
+ switch (new_options) {
+ case WDIOS_DISABLECARD:
+ if (test_bit(WDTS_TIMER_RUN, &wdt_status))
+ wdt_stop();
+ clear_bit(WDTS_TIMER_RUN, &wdt_status);
+ return 0;
+
+ case WDIOS_ENABLECARD:
+ if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
+ wdt_start();
+ return 0;
+
+ default:
+ return -EFAULT;
+ }
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, uarg.i))
+ return -EFAULT;
+ rc = wdt_set_timeout(new_timeout);
+ case WDIOC_GETTIMEOUT:
+ if (put_user(timeout, uarg.i))
+ return -EFAULT;
+ return rc;
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ wdt_stop();
+ return NOTIFY_DONE;
+}
+
+static const struct file_operations wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdt_write,
+ .unlocked_ioctl = wdt_ioctl,
+ .open = wdt_open,
+ .release = wdt_release,
+};
+
+static struct miscdevice wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+
+static int __init it87_wdt_init(void)
+{
+ int rc = 0;
+ u16 chip_type;
+ u8 chip_rev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ chip_type = superio_inw(CHIPID);
+ chip_rev = superio_inb(CHIPREV) & 0x0f;
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ switch (chip_type) {
+ case IT8716_ID:
+ case IT8718_ID:
+ case IT8726_ID:
+ break;
+ case IT8712_ID:
+ if (chip_rev > 7)
+ break;
+ case IT8705_ID:
+ printk(KERN_ERR PFX
+ "Unsupported Chip found, Chip %04x Revision %02x\n",
+ chip_type, chip_rev);
+ return -ENODEV;
+ case NO_DEV_ID:
+ printk(KERN_ERR PFX "no device\n");
+ return -ENODEV;
+ default:
+ printk(KERN_ERR PFX
+ "Unknown Chip found, Chip %04x Revision %04x\n",
+ chip_type, chip_rev);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(GPIO);
+ superio_outb(WDT_TOV1, WDTCFG);
+ superio_outb(0x00, WDTCTRL);
+
+ /* First try to get Gameport support */
+ if (chip_type != IT8718_ID && !nogameport) {
+ superio_select(GAMEPORT);
+ base = superio_inw(BASEREG);
+ if (!base) {
+ base = GP_BASE_DEFAULT;
+ superio_outw(base, BASEREG);
+ }
+ gpact = superio_inb(ACTREG);
+ superio_outb(0x01, ACTREG);
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ if (request_region(base, 1, WATCHDOG_NAME))
+ set_bit(WDTS_USE_GP, &wdt_status);
+ else
+ rc = -EIO;
+ } else {
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+
+ /* If we haven't Gameport support, try to get CIR support */
+ if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
+ if (rc == -EIO)
+ printk(KERN_ERR PFX
+ "I/O Address 0x%04x and 0x%04x"
+ " already in use\n", base, CIR_BASE);
+ else
+ printk(KERN_ERR PFX
+ "I/O Address 0x%04x already in use\n",
+ CIR_BASE);
+ rc = -EIO;
+ goto err_out;
+ }
+ base = CIR_BASE;
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+
+ superio_select(CIR);
+ superio_outw(base, BASEREG);
+ superio_outb(0x00, CIR_ILS);
+ ciract = superio_inb(ACTREG);
+ superio_outb(0x01, ACTREG);
+ if (rc == -EIO) {
+ superio_select(GAMEPORT);
+ superio_outb(gpact, ACTREG);
+ }
+
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+
+ if (timeout < 1 || timeout > 65535) {
+ timeout = DEFAULT_TIMEOUT;
+ printk(KERN_WARNING PFX
+ "Timeout value out of range, use default %d sec\n",
+ DEFAULT_TIMEOUT);
+ }
+
+ rc = register_reboot_notifier(&wdt_notifier);
+ if (rc) {
+ printk(KERN_ERR PFX
+ "Cannot register reboot notifier (err=%d)\n", rc);
+ goto err_out_region;
+ }
+
+ rc = misc_register(&wdt_miscdev);
+ if (rc) {
+ printk(KERN_ERR PFX
+ "Cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_reboot;
+ }
+
+ /* Initialize CIR to use it as keepalive source */
+ if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ outb(0x00, CIR_RCR(base));
+ outb(0xc0, CIR_TCR1(base));
+ outb(0x5c, CIR_TCR2(base));
+ outb(0x10, CIR_IER(base));
+ outb(0x00, CIR_BDHR(base));
+ outb(0x01, CIR_BDLR(base));
+ outb(0x09, CIR_IER(base));
+ }
+
+ printk(KERN_INFO PFX "Chip it%04x revision %d initialized. "
+ "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
+ "nogameport=%d)\n", chip_type, chip_rev, timeout,
+ nowayout, testmode, exclusive, nogameport);
+
+ return 0;
+
+err_out_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
+err_out_region:
+ release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+ if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(CIR);
+ superio_outb(ciract, ACTREG);
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+err_out:
+ if (chip_type != IT8718_ID && !nogameport) {
+ spin_lock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(GAMEPORT);
+ superio_outb(gpact, ACTREG);
+ superio_exit();
+ spin_unlock_irqrestore(&spinlock, flags);
+ }
+
+ return rc;
+}
+
+static void __exit it87_wdt_exit(void)
+{
+ unsigned long flags;
+ int nolock;
+
+ nolock = !spin_trylock_irqsave(&spinlock, flags);
+ superio_enter();
+ superio_select(GPIO);
+ superio_outb(0x00, WDTCTRL);
+ superio_outb(0x00, WDTCFG);
+ superio_outb(0x00, WDTVALMSB);
+ superio_outb(0x00, WDTVALLSB);
+ if (test_bit(WDTS_USE_GP, &wdt_status)) {
+ superio_select(GAMEPORT);
+ superio_outb(gpact, ACTREG);
+ } else {
+ superio_select(CIR);
+ superio_outb(ciract, ACTREG);
+ }
+ superio_exit();
+ if (!nolock)
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ misc_deregister(&wdt_miscdev);
+ unregister_reboot_notifier(&wdt_notifier);
+ release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+}
+
+module_init(it87_wdt_init);
+module_exit(it87_wdt_exit);
+
+MODULE_AUTHOR("Oliver Schuster");
+MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3a11dadfd8e..7bcbb7f4745 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/char/watchdog/omap_wdt.c
+ * omap_wdt.c
*
- * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
*
* Author: MontaVista Software, Inc.
* <gdavis@mvista.com> or <source@mvista.com>
@@ -47,50 +47,68 @@
#include "omap_wdt.h"
+static struct platform_device *omap_wdt_dev;
+
static unsigned timer_margin;
module_param(timer_margin, uint, 0);
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
-static int omap_wdt_users;
-static struct clk *armwdt_ck;
-static struct clk *mpu_wdt_ick;
-static struct clk *mpu_wdt_fck;
-
static unsigned int wdt_trgr_pattern = 0x1234;
static spinlock_t wdt_lock;
-static void omap_wdt_ping(void)
+struct omap_wdt_dev {
+ void __iomem *base; /* physical */
+ struct device *dev;
+ int omap_wdt_users;
+ struct clk *armwdt_ck;
+ struct clk *mpu_wdt_ick;
+ struct clk *mpu_wdt_fck;
+ struct resource *mem;
+ struct miscdevice omap_wdt_miscdev;
+};
+
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
{
+ void __iomem *base = wdev->base;
+
/* wait for posted write to complete */
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
+
wdt_trgr_pattern = ~wdt_trgr_pattern;
- omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+ __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+
/* wait for posted write to complete */
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
cpu_relax();
/* reloaded WCRR from WLDR */
}
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
{
+ void __iomem *base = wdev->base;
+
/* Sequence to enable the watchdog */
- omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
- omap_writel(0x4444, OMAP_WATCHDOG_SPR);
- while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+
+ __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+ while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
cpu_relax();
}
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
{
+ void __iomem *base = wdev->base;
+
/* sequence required to disable watchdog */
- omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
- omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+
+ __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
cpu_relax();
}
@@ -103,83 +121,90 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
timer_margin = new_timeout;
}
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
{
u32 pre_margin = GET_WLDR_VAL(timer_margin);
+ void __iomem *base = wdev->base;
/* just count up at 32 KHz */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
- omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+
+ __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
}
/*
* Allow only one task to hold it open
*/
-
static int omap_wdt_open(struct inode *inode, struct file *file)
{
- if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+ struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+ void __iomem *base = wdev->base;
+
+ if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
return -EBUSY;
if (cpu_is_omap16xx())
- clk_enable(armwdt_ck); /* Enable the clock */
+ clk_enable(wdev->armwdt_ck); /* Enable the clock */
- if (cpu_is_omap24xx()) {
- clk_enable(mpu_wdt_ick); /* Enable the interface clock */
- clk_enable(mpu_wdt_fck); /* Enable the functional clock */
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ clk_enable(wdev->mpu_wdt_ick); /* Enable the interface clock */
+ clk_enable(wdev->mpu_wdt_fck); /* Enable the functional clock */
}
/* initialize prescaler */
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
- omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
- while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+
+ __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
- omap_wdt_set_timeout();
- omap_wdt_enable();
+ file->private_data = (void *) wdev;
+
+ omap_wdt_set_timeout(wdev);
+ omap_wdt_enable(wdev);
+
return nonseekable_open(inode, file);
}
static int omap_wdt_release(struct inode *inode, struct file *file)
{
+ struct omap_wdt_dev *wdev = file->private_data;
+
/*
* Shut off the timer unless NOWAYOUT is defined.
*/
#ifndef CONFIG_WATCHDOG_NOWAYOUT
- omap_wdt_disable();
- if (cpu_is_omap16xx()) {
- clk_disable(armwdt_ck); /* Disable the clock */
- clk_put(armwdt_ck);
- armwdt_ck = NULL;
- }
+ omap_wdt_disable(wdev);
- if (cpu_is_omap24xx()) {
- clk_disable(mpu_wdt_ick); /* Disable the clock */
- clk_disable(mpu_wdt_fck); /* Disable the clock */
- clk_put(mpu_wdt_ick);
- clk_put(mpu_wdt_fck);
- mpu_wdt_ick = NULL;
- mpu_wdt_fck = NULL;
+ if (cpu_is_omap16xx())
+ clk_disable(wdev->armwdt_ck); /* Disable the clock */
+
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */
+ clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */
}
#else
printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
#endif
- omap_wdt_users = 0;
+ wdev->omap_wdt_users = 0;
+
return 0;
}
static ssize_t omap_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
+ struct omap_wdt_dev *wdev = file->private_data;
+
/* Refresh LOAD_TIME. */
if (len) {
spin_lock(&wdt_lock);
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
}
return len;
@@ -188,6 +213,7 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data,
static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
+ struct omap_wdt_dev *wdev;
int new_margin;
static const struct watchdog_info ident = {
.identity = "OMAP Watchdog",
@@ -195,6 +221,8 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
.firmware_version = 0,
};
+ wdev = file->private_data;
+
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident,
@@ -203,14 +231,14 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
return put_user(0, (int __user *)arg);
case WDIOC_GETBOOTSTATUS:
if (cpu_is_omap16xx())
- return put_user(omap_readw(ARM_SYSST),
+ return put_user(__raw_readw(ARM_SYSST),
(int __user *)arg);
if (cpu_is_omap24xx())
return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg);
case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
return 0;
case WDIOC_SETTIMEOUT:
@@ -219,11 +247,11 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
omap_wdt_adjust_timeout(new_margin);
spin_lock(&wdt_lock);
- omap_wdt_disable();
- omap_wdt_set_timeout();
- omap_wdt_enable();
+ omap_wdt_disable(wdev);
+ omap_wdt_set_timeout(wdev);
+ omap_wdt_enable(wdev);
- omap_wdt_ping();
+ omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
/* Fall */
case WDIOC_GETTIMEOUT:
@@ -241,96 +269,173 @@ static const struct file_operations omap_wdt_fops = {
.release = omap_wdt_release,
};
-static struct miscdevice omap_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &omap_wdt_fops,
-};
-
static int __init omap_wdt_probe(struct platform_device *pdev)
{
struct resource *res, *mem;
+ struct omap_wdt_dev *wdev;
int ret;
/* reserve static register mappings */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
+ if (!res) {
+ ret = -ENOENT;
+ goto err_get_resource;
+ }
+
+ if (omap_wdt_dev) {
+ ret = -EBUSY;
+ goto err_busy;
+ }
mem = request_mem_region(res->start, res->end - res->start + 1,
pdev->name);
- if (mem == NULL)
- return -EBUSY;
+ if (!mem) {
+ ret = -EBUSY;
+ goto err_busy;
+ }
- platform_set_drvdata(pdev, mem);
+ wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+ if (!wdev) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
- omap_wdt_users = 0;
+ wdev->omap_wdt_users = 0;
+ wdev->mem = mem;
if (cpu_is_omap16xx()) {
- armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
- if (IS_ERR(armwdt_ck)) {
- ret = PTR_ERR(armwdt_ck);
- armwdt_ck = NULL;
- goto fail;
+ wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+ if (IS_ERR(wdev->armwdt_ck)) {
+ ret = PTR_ERR(wdev->armwdt_ck);
+ wdev->armwdt_ck = NULL;
+ goto err_clk;
}
}
if (cpu_is_omap24xx()) {
- mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
- if (IS_ERR(mpu_wdt_ick)) {
- ret = PTR_ERR(mpu_wdt_ick);
- mpu_wdt_ick = NULL;
- goto fail;
+ wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+ if (IS_ERR(wdev->mpu_wdt_ick)) {
+ ret = PTR_ERR(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ goto err_clk;
}
- mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
- if (IS_ERR(mpu_wdt_fck)) {
- ret = PTR_ERR(mpu_wdt_fck);
- mpu_wdt_fck = NULL;
- goto fail;
+ wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+ if (IS_ERR(wdev->mpu_wdt_fck)) {
+ ret = PTR_ERR(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ goto err_clk;
}
}
- omap_wdt_disable();
+ if (cpu_is_omap34xx()) {
+ wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick");
+ if (IS_ERR(wdev->mpu_wdt_ick)) {
+ ret = PTR_ERR(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ goto err_clk;
+ }
+ wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
+ if (IS_ERR(wdev->mpu_wdt_fck)) {
+ ret = PTR_ERR(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ goto err_clk;
+ }
+ }
+ wdev->base = ioremap(res->start, res->end - res->start + 1);
+ if (!wdev->base) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ platform_set_drvdata(pdev, wdev);
+
+ omap_wdt_disable(wdev);
omap_wdt_adjust_timeout(timer_margin);
- omap_wdt_miscdev.parent = &pdev->dev;
- ret = misc_register(&omap_wdt_miscdev);
+ wdev->omap_wdt_miscdev.parent = &pdev->dev;
+ wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+ wdev->omap_wdt_miscdev.name = "watchdog";
+ wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+
+ ret = misc_register(&(wdev->omap_wdt_miscdev));
if (ret)
- goto fail;
+ goto err_misc;
- pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+ pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+ __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+ timer_margin);
/* autogate OCP interface clock */
- omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+ __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+ omap_wdt_dev = pdev;
+
return 0;
-fail:
- if (armwdt_ck)
- clk_put(armwdt_ck);
- if (mpu_wdt_ick)
- clk_put(mpu_wdt_ick);
- if (mpu_wdt_fck)
- clk_put(mpu_wdt_fck);
- release_resource(mem);
+err_misc:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(wdev->base);
+
+err_ioremap:
+ wdev->base = NULL;
+
+err_clk:
+ if (wdev->armwdt_ck)
+ clk_put(wdev->armwdt_ck);
+ if (wdev->mpu_wdt_ick)
+ clk_put(wdev->mpu_wdt_ick);
+ if (wdev->mpu_wdt_fck)
+ clk_put(wdev->mpu_wdt_fck);
+ kfree(wdev);
+
+err_kzalloc:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+err_busy:
+err_get_resource:
+
return ret;
}
static void omap_wdt_shutdown(struct platform_device *pdev)
{
- omap_wdt_disable();
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+ if (wdev->omap_wdt_users)
+ omap_wdt_disable(wdev);
}
static int omap_wdt_remove(struct platform_device *pdev)
{
- struct resource *mem = platform_get_drvdata(pdev);
- misc_deregister(&omap_wdt_miscdev);
- release_resource(mem);
- if (armwdt_ck)
- clk_put(armwdt_ck);
- if (mpu_wdt_ick)
- clk_put(mpu_wdt_ick);
- if (mpu_wdt_fck)
- clk_put(mpu_wdt_fck);
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res)
+ return -ENOENT;
+
+ misc_deregister(&(wdev->omap_wdt_miscdev));
+ release_mem_region(res->start, res->end - res->start + 1);
+ platform_set_drvdata(pdev, NULL);
+
+ if (wdev->armwdt_ck) {
+ clk_put(wdev->armwdt_ck);
+ wdev->armwdt_ck = NULL;
+ }
+
+ if (wdev->mpu_wdt_ick) {
+ clk_put(wdev->mpu_wdt_ick);
+ wdev->mpu_wdt_ick = NULL;
+ }
+
+ if (wdev->mpu_wdt_fck) {
+ clk_put(wdev->mpu_wdt_fck);
+ wdev->mpu_wdt_fck = NULL;
+ }
+ iounmap(wdev->base);
+
+ kfree(wdev);
+ omap_wdt_dev = NULL;
+
return 0;
}
@@ -344,17 +449,23 @@ static int omap_wdt_remove(struct platform_device *pdev)
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
- if (omap_wdt_users)
- omap_wdt_disable();
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+ if (wdev->omap_wdt_users)
+ omap_wdt_disable(wdev);
+
return 0;
}
static int omap_wdt_resume(struct platform_device *pdev)
{
- if (omap_wdt_users) {
- omap_wdt_enable();
- omap_wdt_ping();
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+ if (wdev->omap_wdt_users) {
+ omap_wdt_enable(wdev);
+ omap_wdt_ping(wdev);
}
+
return 0;
}
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index 52a532a5114..fc02ec6a038 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -30,25 +30,15 @@
#ifndef _OMAP_WATCHDOG_H
#define _OMAP_WATCHDOG_H
-#define OMAP1610_WATCHDOG_BASE 0xfffeb000
-#define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE
-#else
-#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE
-#define RM_RSTST_WKUP 0
-#endif
-
-#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00)
-#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10)
-#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14)
-#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24)
-#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28)
-#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c)
-#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30)
-#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34)
-#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48)
+#define OMAP_WATCHDOG_REV (0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG (0x10)
+#define OMAP_WATCHDOG_STATUS (0x14)
+#define OMAP_WATCHDOG_CNTRL (0x24)
+#define OMAP_WATCHDOG_CRR (0x28)
+#define OMAP_WATCHDOG_LDR (0x2c)
+#define OMAP_WATCHDOG_TGR (0x30)
+#define OMAP_WATCHDOG_WPS (0x34)
+#define OMAP_WATCHDOG_SPR (0x48)
/* Using the prescaler, the OMAP watchdog could go for many
* months before firing. These limits work without scaling,
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
new file mode 100644
index 00000000000..14a339f58b6
--- /dev/null
+++ b/drivers/watchdog/orion5x_wdt.c
@@ -0,0 +1,245 @@
+/*
+ * drivers/watchdog/orion5x_wdt.c
+ *
+ * Watchdog driver for Orion5x processors
+ *
+ * Author: Sylver Bruneau <sylver.bruneau@googlemail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define TIMER_CTRL (TIMER_VIRT_BASE + 0x0000)
+#define WDT_EN 0x0010
+#define WDT_VAL (TIMER_VIRT_BASE + 0x0024)
+
+#define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK)
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat = WDT_MAX_DURATION; /* (seconds) */
+static unsigned long wdt_status;
+static spinlock_t wdt_lock;
+
+static void wdt_enable(void)
+{
+ u32 reg;
+
+ spin_lock(&wdt_lock);
+
+ /* Set watchdog duration */
+ writel(ORION5X_TCLK * heartbeat, WDT_VAL);
+
+ /* Clear watchdog timer interrupt */
+ reg = readl(BRIDGE_CAUSE);
+ reg &= ~WDT_INT_REQ;
+ writel(reg, BRIDGE_CAUSE);
+
+ /* Enable watchdog timer */
+ reg = readl(TIMER_CTRL);
+ reg |= WDT_EN;
+ writel(reg, TIMER_CTRL);
+
+ /* Enable reset on watchdog */
+ reg = readl(CPU_RESET_MASK);
+ reg |= WDT_RESET;
+ writel(reg, CPU_RESET_MASK);
+
+ spin_unlock(&wdt_lock);
+}
+
+static void wdt_disable(void)
+{
+ u32 reg;
+
+ spin_lock(&wdt_lock);
+
+ /* Disable reset on watchdog */
+ reg = readl(CPU_RESET_MASK);
+ reg &= ~WDT_RESET;
+ writel(reg, CPU_RESET_MASK);
+
+ /* Disable watchdog timer */
+ reg = readl(TIMER_CTRL);
+ reg &= ~WDT_EN;
+ writel(reg, TIMER_CTRL);
+
+ spin_unlock(&wdt_lock);
+}
+
+static int orion5x_wdt_get_timeleft(int *time_left)
+{
+ spin_lock(&wdt_lock);
+ *time_left = readl(WDT_VAL) / ORION5X_TCLK;
+ spin_unlock(&wdt_lock);
+ return 0;
+}
+
+static int orion5x_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ wdt_enable();
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t orion5x_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+ wdt_enable();
+ }
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING,
+ .identity = "Orion5x Watchdog",
+};
+
+
+static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+ int time;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_enable();
+ ret = 0;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(time, (int *)arg);
+ if (ret)
+ break;
+
+ if (time <= 0 || time > WDT_MAX_DURATION) {
+ ret = -EINVAL;
+ break;
+ }
+ heartbeat = time;
+ wdt_enable();
+ /* Fall through */
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMELEFT:
+ if (orion5x_wdt_get_timeleft(&time)) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = put_user(time, (int *)arg);
+ break;
+ }
+ return ret;
+}
+
+static int orion5x_wdt_release(struct inode *inode, struct file *file)
+{
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ wdt_disable();
+ else
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+ "timer will not stop\n");
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+
+static const struct file_operations orion5x_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = orion5x_wdt_write,
+ .unlocked_ioctl = orion5x_wdt_ioctl,
+ .open = orion5x_wdt_open,
+ .release = orion5x_wdt_release,
+};
+
+static struct miscdevice orion5x_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &orion5x_wdt_fops,
+};
+
+static int __init orion5x_wdt_init(void)
+{
+ int ret;
+
+ spin_lock_init(&wdt_lock);
+
+ ret = misc_register(&orion5x_wdt_miscdev);
+ if (ret == 0)
+ printk("Orion5x Watchdog Timer: heartbeat %d sec\n",
+ heartbeat);
+
+ return ret;
+}
+
+static void __exit orion5x_wdt_exit(void)
+{
+ misc_deregister(&orion5x_wdt_miscdev);
+}
+
+module_init(orion5x_wdt_init);
+module_exit(orion5x_wdt_exit);
+
+MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
+MODULE_DESCRIPTION("Orion5x Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is "
+ __MODULE_STRING(WDT_MAX_DURATION) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/watchdog/riowd.c
index 88c0fc6395e..09cb1833ea2 100644
--- a/drivers/sbus/char/riowatchdog.c
+++ b/drivers/watchdog/riowd.c
@@ -1,7 +1,6 @@
-/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $
- * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
+/* riowd.c - driver for hw watchdog inside Super I/O of RIO
*
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -12,14 +11,13 @@
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
+#include <linux/watchdog.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/bbc.h>
-#include <asm/oplib.h>
#include <asm/uaccess.h>
-#include <asm/watchdog.h>
/* RIO uses the NatSemi Super I/O power management logical device
* as its' watchdog.
@@ -45,74 +43,35 @@
* The watchdog device generates no interrupts.
*/
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
MODULE_SUPPORTED_DEVICE("watchdog");
MODULE_LICENSE("GPL");
-#define RIOWD_NAME "pmc"
-#define RIOWD_MINOR 215
+#define DRIVER_NAME "riowd"
+#define PFX DRIVER_NAME ": "
-static DEFINE_SPINLOCK(riowd_lock);
+struct riowd {
+ void __iomem *regs;
+ spinlock_t lock;
+};
+
+static struct riowd *riowd_device;
-static void __iomem *bbc_regs;
-static void __iomem *riowd_regs;
#define WDTO_INDEX 0x05
static int riowd_timeout = 1; /* in minutes */
module_param(riowd_timeout, int, 0);
MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
-#if 0 /* Currently unused. */
-static u8 riowd_readreg(int index)
+static void riowd_writereg(struct riowd *p, u8 val, int index)
{
unsigned long flags;
- u8 ret;
- spin_lock_irqsave(&riowd_lock, flags);
- writeb(index, riowd_regs + 0);
- ret = readb(riowd_regs + 1);
- spin_unlock_irqrestore(&riowd_lock, flags);
-
- return ret;
-}
-#endif
-
-static void riowd_writereg(u8 val, int index)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&riowd_lock, flags);
- writeb(index, riowd_regs + 0);
- writeb(val, riowd_regs + 1);
- spin_unlock_irqrestore(&riowd_lock, flags);
-}
-
-static void riowd_pingtimer(void)
-{
- riowd_writereg(riowd_timeout, WDTO_INDEX);
-}
-
-static void riowd_stoptimer(void)
-{
- u8 val;
-
- riowd_writereg(0, WDTO_INDEX);
-
- val = readb(bbc_regs + BBC_WDACTION);
- val &= ~BBC_WDACTION_RST;
- writeb(val, bbc_regs + BBC_WDACTION);
-}
-
-static void riowd_starttimer(void)
-{
- u8 val;
-
- riowd_writereg(riowd_timeout, WDTO_INDEX);
-
- val = readb(bbc_regs + BBC_WDACTION);
- val |= BBC_WDACTION_RST;
- writeb(val, bbc_regs + BBC_WDACTION);
+ spin_lock_irqsave(&p->lock, flags);
+ writeb(index, p->regs + 0);
+ writeb(val, p->regs + 1);
+ spin_unlock_irqrestore(&p->lock, flags);
}
static int riowd_open(struct inode *inode, struct file *filp)
@@ -131,9 +90,12 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
static struct watchdog_info info = {
- WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317"
+ .options = WDIOF_SETTIMEOUT,
+ .firmware_version = 1,
+ .identity = DRIVER_NAME,
};
void __user *argp = (void __user *)arg;
+ struct riowd *p = riowd_device;
unsigned int options;
int new_margin;
@@ -150,7 +112,7 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
break;
case WDIOC_KEEPALIVE:
- riowd_pingtimer();
+ riowd_writereg(p, riowd_timeout, WDTO_INDEX);
break;
case WDIOC_SETOPTIONS:
@@ -158,9 +120,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
return -EFAULT;
if (options & WDIOS_DISABLECARD)
- riowd_stoptimer();
+ riowd_writereg(p, 0, WDTO_INDEX);
else if (options & WDIOS_ENABLECARD)
- riowd_starttimer();
+ riowd_writereg(p, riowd_timeout, WDTO_INDEX);
else
return -EINVAL;
@@ -170,9 +132,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
if (get_user(new_margin, (int __user *)argp))
return -EFAULT;
if ((new_margin < 60) || (new_margin > (255 * 60)))
- return -EINVAL;
+ return -EINVAL;
riowd_timeout = (new_margin + 59) / 60;
- riowd_pingtimer();
+ riowd_writereg(p, riowd_timeout, WDTO_INDEX);
/* Fall */
case WDIOC_GETTIMEOUT:
@@ -187,8 +149,10 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
+ struct riowd *p = riowd_device;
+
if (count) {
- riowd_pingtimer();
+ riowd_writereg(p, riowd_timeout, WDTO_INDEX);
return 1;
}
@@ -197,99 +161,99 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou
static const struct file_operations riowd_fops = {
.owner = THIS_MODULE,
+ .llseek = no_llseek,
.ioctl = riowd_ioctl,
.open = riowd_open,
.write = riowd_write,
.release = riowd_release,
};
-static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops };
+static struct miscdevice riowd_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &riowd_fops
+};
-static int __init riowd_bbc_init(void)
+static int __devinit riowd_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
- u8 val;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->ofdev.node->name, "bbc"))
- goto found_bbc;
- }
- }
+ struct riowd *p;
+ int err = -EINVAL;
-found_bbc:
- if (!edev)
- return -ENODEV;
- bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE);
- if (!bbc_regs)
- return -ENODEV;
+ if (riowd_device)
+ goto out;
- /* Turn it off. */
- val = readb(bbc_regs + BBC_WDACTION);
- val &= ~BBC_WDACTION_RST;
- writeb(val, bbc_regs + BBC_WDACTION);
+ err = -ENOMEM;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ goto out;
- return 0;
-}
+ spin_lock_init(&p->lock);
-static int __init riowd_init(void)
-{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->ofdev.node->name, RIOWD_NAME))
- goto ebus_done;
- }
+ p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
+ if (!p->regs) {
+ printk(KERN_ERR PFX "Cannot map registers.\n");
+ goto out_free;
}
-ebus_done:
- if (!edev)
- goto fail;
-
- riowd_regs = ioremap(edev->resource[0].start, 2);
- if (riowd_regs == NULL) {
- printk(KERN_ERR "pmc: Cannot map registers.\n");
- return -ENODEV;
+ err = misc_register(&riowd_miscdev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+ goto out_iounmap;
}
- if (riowd_bbc_init()) {
- printk(KERN_ERR "pmc: Failure initializing BBC config.\n");
- goto fail;
- }
+ printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
+ "regs at %p\n", riowd_timeout, p->regs);
- if (misc_register(&riowd_miscdev)) {
- printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n");
- goto fail;
- }
+ dev_set_drvdata(&op->dev, p);
+ riowd_device = p;
+ err = 0;
- printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], "
- "regs at %p\n", riowd_timeout, riowd_regs);
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, 2);
- return 0;
+out_free:
+ kfree(p);
-fail:
- if (riowd_regs) {
- iounmap(riowd_regs);
- riowd_regs = NULL;
- }
- if (bbc_regs) {
- iounmap(bbc_regs);
- bbc_regs = NULL;
- }
- return -ENODEV;
+out:
+ return err;
}
-static void __exit riowd_cleanup(void)
+static int __devexit riowd_remove(struct of_device *op)
{
+ struct riowd *p = dev_get_drvdata(&op->dev);
+
misc_deregister(&riowd_miscdev);
- iounmap(riowd_regs);
- riowd_regs = NULL;
- iounmap(bbc_regs);
- bbc_regs = NULL;
+ of_iounmap(&op->resource[0], p->regs, 2);
+ kfree(p);
+
+ return 0;
+}
+
+static const struct of_device_id riowd_match[] = {
+ {
+ .name = "pmc",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, riowd_match);
+
+static struct of_platform_driver riowd_driver = {
+ .name = DRIVER_NAME,
+ .match_table = riowd_match,
+ .probe = riowd_probe,
+ .remove = __devexit_p(riowd_remove),
+};
+
+static int __init riowd_init(void)
+{
+ return of_register_driver(&riowd_driver, &of_bus_type);
+}
+
+static void __exit riowd_exit(void)
+{
+ of_unregister_driver(&riowd_driver);
}
module_init(riowd_init);
-module_exit(riowd_cleanup);
+module_exit(riowd_exit);
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
new file mode 100644
index 00000000000..c73b5e2919c
--- /dev/null
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -0,0 +1,392 @@
+/*
+ * w83697ug/uf WDT driver
+ *
+ * (c) Copyright 2008 Flemming Fransen <ff@nrvissing.net>
+ * reused original code to supoprt w83697ug/uf.
+ *
+ * Based on w83627hf_wdt.c which is based on advantechwdt.c
+ * which is based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
+ * added support for W83627THF.
+ *
+ * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ *
+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_NAME "w83697ug/uf WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
+
+static unsigned long wdt_is_open;
+static char expect_close;
+static DEFINE_SPINLOCK(io_lock);
+
+static int wdt_io = 0x2e;
+module_param(wdt_io, int, 0);
+MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)");
+
+static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+ "Watchdog timeout in seconds. 1<= timeout <=255 (default="
+ __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ * Kernel methods.
+ */
+
+#define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */
+#define WDT_EFIR (wdt_io+0) /* Extended Function Index Register
+ (same as EFER) */
+#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
+
+static void w83697ug_select_wd_register(void)
+{
+ unsigned char c;
+ unsigned char version;
+
+ outb_p(0x87, WDT_EFER); /* Enter extended function mode */
+ outb_p(0x87, WDT_EFER); /* Again according to manual */
+
+ outb(0x20, WDT_EFER); /* check chip version */
+ version = inb(WDT_EFDR);
+
+ if (version == 0x68) { /* W83697UG */
+ printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
+ "W83697UG/UF found at 0x%04x\n", version, wdt_io);
+
+ outb_p(0x2b, WDT_EFER);
+ c = inb_p(WDT_EFDR); /* select WDT0 */
+ c &= ~0x04;
+ outb_p(0x2b, WDT_EFER);
+ outb_p(c, WDT_EFDR); /* set pin118 to WDT0 */
+
+ } else {
+ printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+ return -EIO;
+ }
+
+ outb_p(0x07, WDT_EFER); /* point to logical device number reg */
+ outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
+ outb_p(0x30, WDT_EFER); /* select CR30 */
+ c = inb_p(WDT_EFDR);
+ outb_p(c || 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
+}
+
+static void w83697ug_unselect_wd_register(void)
+{
+ outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
+}
+
+static void w83697ug_init(void)
+{
+ unsigned char t;
+
+ w83697ug_select_wd_register();
+
+ outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+ t = inb_p(WDT_EFDR); /* read CRF6 */
+ if (t != 0) {
+ printk(KERN_INFO PFX "Watchdog already running."
+ " Resetting timeout to %d sec\n", timeout);
+ outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
+ }
+ outb_p(0xF5, WDT_EFER); /* Select CRF5 */
+ t = inb_p(WDT_EFDR); /* read CRF5 */
+ t &= ~0x0C; /* set second mode &
+ disable keyboard turning off watchdog */
+ outb_p(t, WDT_EFDR); /* Write back to CRF5 */
+
+ w83697ug_unselect_wd_register();
+}
+
+static void wdt_ctrl(int timeout)
+{
+ spin_lock(&io_lock);
+
+ w83697ug_select_wd_register();
+
+ outb_p(0xF4, WDT_EFER); /* Select CRF4 */
+ outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
+
+ w83697ug_unselect_wd_register();
+
+ spin_unlock(&io_lock);
+}
+
+static int wdt_ping(void)
+{
+ wdt_ctrl(timeout);
+ return 0;
+}
+
+static int wdt_disable(void)
+{
+ wdt_ctrl(0);
+ return 0;
+}
+
+static int wdt_set_heartbeat(int t)
+{
+ if (t < 1 || t > 255)
+ return -EINVAL;
+
+ timeout = t;
+ return 0;
+}
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
+ wdt_ping();
+ }
+ return count;
+}
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_timeout;
+ static const struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 1,
+ .identity = "W83697UG WDT",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &ident, sizeof(ident)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_SETOPTIONS:
+ {
+ int options, retval = -EINVAL;
+
+ if (get_user(options, p))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ wdt_disable();
+ retval = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ wdt_ping();
+ retval = 0;
+ }
+
+ return retval;
+ }
+
+ case WDIOC_KEEPALIVE:
+ wdt_ping();
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, p))
+ return -EFAULT;
+ if (wdt_set_heartbeat(new_timeout))
+ return -EINVAL;
+ wdt_ping();
+ /* Fall */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, p);
+
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &wdt_is_open))
+ return -EBUSY;
+ /*
+ * Activate
+ */
+
+ wdt_ping();
+ return nonseekable_open(inode, file);
+}
+
+static int wdt_close(struct inode *inode, struct file *file)
+{
+ if (expect_close == 42)
+ wdt_disable();
+ else {
+ printk(KERN_CRIT PFX
+ "Unexpected close, not stopping watchdog!\n");
+ wdt_ping();
+ }
+ expect_close = 0;
+ clear_bit(0, &wdt_is_open);
+ return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ wdt_disable(); /* Turn the WDT off */
+
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static const struct file_operations wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdt_write,
+ .unlocked_ioctl = wdt_ioctl,
+ .open = wdt_open,
+ .release = wdt_close,
+};
+
+static struct miscdevice wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdt_fops,
+};
+
+/*
+ * The WDT needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+
+static int __init wdt_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+
+ if (wdt_set_heartbeat(timeout)) {
+ wdt_set_heartbeat(WATCHDOG_TIMEOUT);
+ printk(KERN_INFO PFX
+ "timeout value must be 1<=timeout<=255, using %d\n",
+ WATCHDOG_TIMEOUT);
+ }
+
+ if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ wdt_io);
+ ret = -EIO;
+ goto out;
+ }
+
+ w83697ug_init();
+
+ ret = register_reboot_notifier(&wdt_notifier);
+ if (ret != 0) {
+ printk(KERN_ERR PFX
+ "cannot register reboot notifier (err=%d)\n", ret);
+ goto unreg_regions;
+ }
+
+ ret = misc_register(&wdt_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX
+ "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto unreg_reboot;
+ }
+
+ printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
+
+out:
+ return ret;
+unreg_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
+unreg_regions:
+ release_region(wdt_io, 1);
+ goto out;
+}
+
+static void __exit wdt_exit(void)
+{
+ misc_deregister(&wdt_miscdev);
+ unregister_reboot_notifier(&wdt_notifier);
+ release_region(wdt_io, 1);
+}
+
+module_init(wdt_init);
+module_exit(wdt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>");
+MODULE_DESCRIPTION("w83697ug/uf WDT driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 363286c5429..d2a8fdf0e19 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,4 +1,5 @@
obj-y += grant-table.o features.o events.o manage.o
obj-y += xenbus/
+obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
obj-$(CONFIG_XEN_BALLOON) += balloon.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 2e15da5459c..8c83abc7340 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -53,7 +53,6 @@
#include <asm/tlb.h>
#include <xen/interface/memory.h>
-#include <xen/balloon.h>
#include <xen/xenbus.h>
#include <xen/features.h>
#include <xen/page.h>
@@ -226,9 +225,8 @@ static int increase_reservation(unsigned long nr_pages)
}
set_xen_guest_handle(reservation.extent_start, frame_list);
- reservation.nr_extents = nr_pages;
- rc = HYPERVISOR_memory_op(
- XENMEM_populate_physmap, &reservation);
+ reservation.nr_extents = nr_pages;
+ rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
if (rc < nr_pages) {
if (rc > 0) {
int ret;
@@ -236,7 +234,7 @@ static int increase_reservation(unsigned long nr_pages)
/* We hit the Xen hard limit: reprobe. */
reservation.nr_extents = rc;
ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
- &reservation);
+ &reservation);
BUG_ON(ret != rc);
}
if (rc >= 0)
@@ -420,7 +418,7 @@ static int __init balloon_init(void)
unsigned long pfn;
struct page *page;
- if (!is_running_on_xen())
+ if (!xen_pv_domain())
return -ENODEV;
pr_info("xen_balloon: Initialising balloon driver.\n");
@@ -464,136 +462,13 @@ static void balloon_exit(void)
module_exit(balloon_exit);
-static void balloon_update_driver_allowance(long delta)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&balloon_lock, flags);
- balloon_stats.driver_pages += delta;
- spin_unlock_irqrestore(&balloon_lock, flags);
-}
-
-static int dealloc_pte_fn(
- pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
-{
- unsigned long mfn = pte_mfn(*pte);
- int ret;
- struct xen_memory_reservation reservation = {
- .nr_extents = 1,
- .extent_order = 0,
- .domid = DOMID_SELF
- };
- set_xen_guest_handle(reservation.extent_start, &mfn);
- set_pte_at(&init_mm, addr, pte, __pte_ma(0ull));
- set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
- BUG_ON(ret != 1);
- return 0;
-}
-
-static struct page **alloc_empty_pages_and_pagevec(int nr_pages)
-{
- unsigned long vaddr, flags;
- struct page *page, **pagevec;
- int i, ret;
-
- pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
- if (pagevec == NULL)
- return NULL;
-
- for (i = 0; i < nr_pages; i++) {
- page = pagevec[i] = alloc_page(GFP_KERNEL);
- if (page == NULL)
- goto err;
-
- vaddr = (unsigned long)page_address(page);
-
- scrub_page(page);
-
- spin_lock_irqsave(&balloon_lock, flags);
-
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
- unsigned long gmfn = page_to_pfn(page);
- struct xen_memory_reservation reservation = {
- .nr_extents = 1,
- .extent_order = 0,
- .domid = DOMID_SELF
- };
- set_xen_guest_handle(reservation.extent_start, &gmfn);
- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
- &reservation);
- if (ret == 1)
- ret = 0; /* success */
- } else {
- ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
- dealloc_pte_fn, NULL);
- }
-
- if (ret != 0) {
- spin_unlock_irqrestore(&balloon_lock, flags);
- __free_page(page);
- goto err;
- }
-
- totalram_pages = --balloon_stats.current_pages;
-
- spin_unlock_irqrestore(&balloon_lock, flags);
- }
-
- out:
- schedule_work(&balloon_worker);
- flush_tlb_all();
- return pagevec;
-
- err:
- spin_lock_irqsave(&balloon_lock, flags);
- while (--i >= 0)
- balloon_append(pagevec[i]);
- spin_unlock_irqrestore(&balloon_lock, flags);
- kfree(pagevec);
- pagevec = NULL;
- goto out;
-}
-
-static void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
-{
- unsigned long flags;
- int i;
-
- if (pagevec == NULL)
- return;
-
- spin_lock_irqsave(&balloon_lock, flags);
- for (i = 0; i < nr_pages; i++) {
- BUG_ON(page_count(pagevec[i]) != 1);
- balloon_append(pagevec[i]);
- }
- spin_unlock_irqrestore(&balloon_lock, flags);
-
- kfree(pagevec);
-
- schedule_work(&balloon_worker);
-}
-
-static void balloon_release_driver_page(struct page *page)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&balloon_lock, flags);
- balloon_append(page);
- balloon_stats.driver_pages--;
- spin_unlock_irqrestore(&balloon_lock, flags);
-
- schedule_work(&balloon_worker);
-}
-
-
-#define BALLOON_SHOW(name, format, args...) \
- static ssize_t show_##name(struct sys_device *dev, \
- char *buf) \
- { \
- return sprintf(buf, format, ##args); \
- } \
+#define BALLOON_SHOW(name, format, args...) \
+ static ssize_t show_##name(struct sys_device *dev, \
+ struct sysdev_attribute *attr, \
+ char *buf) \
+ { \
+ return sprintf(buf, format, ##args); \
+ } \
static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
@@ -604,7 +479,8 @@ BALLOON_SHOW(hard_limit_kb,
(balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
-static ssize_t show_target_kb(struct sys_device *dev, char *buf)
+static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
}
@@ -614,19 +490,14 @@ static ssize_t store_target_kb(struct sys_device *dev,
const char *buf,
size_t count)
{
- char memstring[64], *endchar;
+ char *endchar;
unsigned long long target_bytes;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (count <= 1)
- return -EBADMSG; /* runt */
- if (count > sizeof(memstring))
- return -EFBIG; /* too long */
- strcpy(memstring, buf);
+ target_bytes = memparse(buf, &endchar);
- target_bytes = memparse(memstring, &endchar);
balloon_set_new_target(target_bytes >> PAGE_SHIFT);
return count;
@@ -694,20 +565,4 @@ static int register_balloon(struct sys_device *sysdev)
return error;
}
-static void unregister_balloon(struct sys_device *sysdev)
-{
- int i;
-
- sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
- for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
- sysdev_remove_file(sysdev, balloon_attrs[i]);
- sysdev_unregister(sysdev);
- sysdev_class_unregister(&balloon_sysdev_class);
-}
-
-static void balloon_sysfs_exit(void)
-{
- unregister_balloon(&balloon_sysdev);
-}
-
MODULE_LICENSE("GPL");
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
new file mode 100644
index 00000000000..565280ec1c6
--- /dev/null
+++ b/drivers/xen/cpu_hotplug.c
@@ -0,0 +1,90 @@
+#include <linux/notifier.h>
+
+#include <xen/xenbus.h>
+
+#include <asm-x86/xen/hypervisor.h>
+#include <asm/cpu.h>
+
+static void enable_hotplug_cpu(int cpu)
+{
+ if (!cpu_present(cpu))
+ arch_register_cpu(cpu);
+
+ cpu_set(cpu, cpu_present_map);
+}
+
+static void disable_hotplug_cpu(int cpu)
+{
+ if (cpu_present(cpu))
+ arch_unregister_cpu(cpu);
+
+ cpu_clear(cpu, cpu_present_map);
+}
+
+static void vcpu_hotplug(unsigned int cpu)
+{
+ int err;
+ char dir[32], state[32];
+
+ if (!cpu_possible(cpu))
+ return;
+
+ sprintf(dir, "cpu/%u", cpu);
+ err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
+ if (err != 1) {
+ printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
+ return;
+ }
+
+ if (strcmp(state, "online") == 0) {
+ enable_hotplug_cpu(cpu);
+ } else if (strcmp(state, "offline") == 0) {
+ (void)cpu_down(cpu);
+ disable_hotplug_cpu(cpu);
+ } else {
+ printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
+ state, cpu);
+ }
+}
+
+static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ unsigned int cpu;
+ char *cpustr;
+ const char *node = vec[XS_WATCH_PATH];
+
+ cpustr = strstr(node, "cpu/");
+ if (cpustr != NULL) {
+ sscanf(cpustr, "cpu/%u", &cpu);
+ vcpu_hotplug(cpu);
+ }
+}
+
+static int setup_cpu_watcher(struct notifier_block *notifier,
+ unsigned long event, void *data)
+{
+ static struct xenbus_watch cpu_watch = {
+ .node = "cpu",
+ .callback = handle_vcpu_hotplug_event};
+
+ (void)register_xenbus_watch(&cpu_watch);
+
+ return NOTIFY_DONE;
+}
+
+static int __init setup_vcpu_hotplug_event(void)
+{
+ static struct notifier_block xsn_cpu = {
+ .notifier_call = setup_cpu_watcher };
+
+ if (!xen_pv_domain())
+ return -ENODEV;
+
+ register_xenstore_notifier(&xsn_cpu);
+
+ return 0;
+}
+
+arch_initcall(setup_vcpu_hotplug_event);
+
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 0e0c28574af..c3290bc186a 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -84,17 +84,6 @@ static int irq_bindcount[NR_IRQS];
/* Xen will never allocate port zero for any purpose. */
#define VALID_EVTCHN(chn) ((chn) != 0)
-/*
- * Force a proper event-channel callback from Xen after clearing the
- * callback mask. We do this in a very simple manner, by making a call
- * down into Xen. The pending flag will be checked by Xen on return.
- */
-void force_evtchn_callback(void)
-{
- (void)HYPERVISOR_xen_version(0, NULL);
-}
-EXPORT_SYMBOL_GPL(force_evtchn_callback);
-
static struct irq_chip xen_dynamic_chip;
/* Constructor for packed IRQ information. */
@@ -175,6 +164,12 @@ static inline void set_evtchn(int port)
sync_set_bit(port, &s->evtchn_pending[0]);
}
+static inline int test_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ return sync_test_bit(port, &s->evtchn_pending[0]);
+}
+
/**
* notify_remote_via_irq - send event to remote end of event channel via irq
@@ -365,6 +360,10 @@ static void unbind_from_irq(unsigned int irq)
per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
[index_from_irq(irq)] = -1;
break;
+ case IRQT_IPI:
+ per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
+ [index_from_irq(irq)] = -1;
+ break;
default:
break;
}
@@ -743,6 +742,25 @@ void xen_clear_irq_pending(int irq)
clear_evtchn(evtchn);
}
+void xen_set_irq_pending(int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ set_evtchn(evtchn);
+}
+
+bool xen_test_irq_pending(int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+ bool ret = false;
+
+ if (VALID_EVTCHN(evtchn))
+ ret = test_evtchn(evtchn);
+
+ return ret;
+}
+
/* Poll waiting for an irq to become pending. In the usual case, the
irq will be disabled so it won't deliver an interrupt. */
void xen_poll_irq(int irq)
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index e9e11168616..06592b9da83 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -508,7 +508,7 @@ static int __devinit gnttab_init(void)
unsigned int max_nr_glist_frames, nr_glist_frames;
unsigned int nr_init_grefs;
- if (!is_running_on_xen())
+ if (!xen_domain())
return -ENODEV;
nr_grant_frames = 1;
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 57ceb5346b7..7f24a98a446 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -814,7 +814,7 @@ static int __init xenbus_probe_init(void)
DPRINTK("");
err = -ENODEV;
- if (!is_running_on_xen())
+ if (!xen_domain())
goto out_error;
/* Register ourselves with the kernel bus subsystem */
@@ -829,7 +829,7 @@ static int __init xenbus_probe_init(void)
/*
* Domain0 doesn't have a store_evtchn or store_mfn yet.
*/
- if (is_initial_xendomain()) {
+ if (xen_initial_domain()) {
/* dom0 not yet supported */
} else {
xenstored_ready = 1;
@@ -846,7 +846,7 @@ static int __init xenbus_probe_init(void)
goto out_unreg_back;
}
- if (!is_initial_xendomain())
+ if (!xen_initial_domain())
xenbus_probe(NULL);
return 0;
@@ -937,7 +937,7 @@ static void wait_for_devices(struct xenbus_driver *xendrv)
unsigned long timeout = jiffies + 10*HZ;
struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
- if (!ready_to_wait_for_devices || !is_running_on_xen())
+ if (!ready_to_wait_for_devices || !xen_domain())
return;
while (exists_disconnected_device(drv)) {
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 047c791427a..c061c3f18e7 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -55,7 +55,7 @@ enum {
Opt_err
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_debug, "debug=%x"},
{Opt_dfltuid, "dfltuid=%u"},
{Opt_dfltgid, "dfltgid=%u"},
diff --git a/fs/Kconfig b/fs/Kconfig
index 40183d94b68..f54a157a029 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -170,8 +170,8 @@ config EXT4DEV_COMPAT
help
Starting with 2.6.28, the name of the ext4 filesystem was
renamed from ext4dev to ext4. Unfortunately there are some
- lagecy userspace programs (such as klibc's fstype) have
- "ext4dev" hardcoded.
+ legacy userspace programs (such as klibc's fstype) have
+ "ext4dev" hardcoded.
To enable backwards compatibility so that systems that are
still expecting to mount ext4 filesystems using ext4dev,
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 4a551af6f3f..17c9c5ec14c 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -59,10 +59,12 @@ config BINFMT_SHARED_FLAT
help
Support FLAT shared libraries
+config HAVE_AOUT
+ def_bool n
+
config BINFMT_AOUT
tristate "Kernel support for a.out and ECOFF binaries"
- depends on ARCH_SUPPORTS_AOUT && \
- (X86_32 || ALPHA || ARM || M68K)
+ depends on HAVE_AOUT
---help---
A.out (Assembler.OUTput) is a set of formats for libraries and
executables used in the earliest versions of UNIX. Linux used
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 26f3b43726b..7f83a46f2b7 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -157,7 +157,7 @@ static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{Opt_ownmask, "ownmask=%o"},
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 3a89094f93d..8989c93193e 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -135,7 +135,7 @@ enum {
Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_bs, "bs=%u"},
{Opt_mode, "mode=%o"},
{Opt_mufs, "mufs"},
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 250d8c4d66e..aee239a048c 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -64,7 +64,7 @@ enum {
afs_opt_vol,
};
-static match_table_t afs_options_list = {
+static const match_table_t afs_options_list = {
{ afs_opt_cell, "cell=%s" },
{ afs_opt_rwpath, "rwpath" },
{ afs_opt_vol, "vol=%s" },
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index dda510d31f8..b70eea1e8c5 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -59,7 +59,7 @@ static const struct super_operations autofs_sops = {
enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
-static match_table_t autofs_tokens = {
+static const match_table_t autofs_tokens = {
{Opt_fd, "fd=%u"},
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 7bb3e5ba053..45d55819203 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -213,7 +213,7 @@ static const struct super_operations autofs4_sops = {
enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
Opt_indirect, Opt_direct, Opt_offset};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_fd, "fd=%u"},
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 740f53672a8..9286b2af893 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -650,7 +650,7 @@ enum {
Opt_uid, Opt_gid, Opt_charset, Opt_debug, Opt_err,
};
-static match_table_t befs_tokens = {
+static const match_table_t befs_tokens = {
{Opt_uid, "uid=%d"},
{Opt_gid, "gid=%d"},
{Opt_charset, "iocharset=%s"},
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 654d972a88f..88786ba02d2 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -311,8 +311,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
buffer->Pid = cpu_to_le16((__u16)current->tgid);
buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
- spin_lock(&GlobalMid_Lock);
- spin_unlock(&GlobalMid_Lock);
if (treeCon) {
buffer->Tid = treeCon->tid;
if (treeCon->ses) {
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 08e28c9bb41..3dbe2169cf3 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -26,8 +26,7 @@
#include <linux/debugfs.h>
#include <linux/fsnotify.h>
#include <linux/string.h>
-
-#define DEBUGFS_MAGIC 0x64626720
+#include <linux/magic.h>
static struct vfsmount *debugfs_mount;
static int debugfs_mount_count;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 488eb424f66..4a714f6c1be 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -27,6 +27,7 @@
#define DEVPTS_SUPER_MAGIC 0x1cd1
#define DEVPTS_DEFAULT_MODE 0600
+#define PTMX_MINOR 2
extern int pty_limit; /* Config limit on Unix98 ptys */
static DEFINE_IDA(allocated_ptys);
@@ -48,7 +49,7 @@ enum {
Opt_err
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{Opt_mode, "mode=%o"},
@@ -169,15 +170,7 @@ static struct file_system_type devpts_fs_type = {
* to the System V naming convention
*/
-static struct dentry *get_node(int num)
-{
- char s[12];
- struct dentry *root = devpts_root;
- mutex_lock(&root->d_inode->i_mutex);
- return lookup_one_len(s, root, sprintf(s, "%d", num));
-}
-
-int devpts_new_index(void)
+int devpts_new_index(struct inode *ptmx_inode)
{
int index;
int ida_ret;
@@ -205,20 +198,21 @@ retry:
return index;
}
-void devpts_kill_index(int idx)
+void devpts_kill_index(struct inode *ptmx_inode, int idx)
{
mutex_lock(&allocated_ptys_lock);
ida_remove(&allocated_ptys, idx);
mutex_unlock(&allocated_ptys_lock);
}
-int devpts_pty_new(struct tty_struct *tty)
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
{
int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
struct tty_driver *driver = tty->driver;
dev_t device = MKDEV(driver->major, driver->minor_start+number);
struct dentry *dentry;
struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+ char s[12];
/* We're supposed to be given the slave end of a pty */
BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
@@ -233,10 +227,15 @@ int devpts_pty_new(struct tty_struct *tty)
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
init_special_inode(inode, S_IFCHR|config.mode, device);
inode->i_private = tty;
+ tty->driver_data = inode;
- dentry = get_node(number);
- if (!IS_ERR(dentry) && !dentry->d_inode) {
- d_instantiate(dentry, inode);
+ sprintf(s, "%d", number);
+
+ mutex_lock(&devpts_root->d_inode->i_mutex);
+
+ dentry = d_alloc_name(devpts_root, s);
+ if (!IS_ERR(dentry)) {
+ d_add(dentry, inode);
fsnotify_create(devpts_root->d_inode, dentry);
}
@@ -245,36 +244,31 @@ int devpts_pty_new(struct tty_struct *tty)
return 0;
}
-struct tty_struct *devpts_get_tty(int number)
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
{
- struct dentry *dentry = get_node(number);
- struct tty_struct *tty;
-
- tty = NULL;
- if (!IS_ERR(dentry)) {
- if (dentry->d_inode)
- tty = dentry->d_inode->i_private;
- dput(dentry);
- }
+ BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
- mutex_unlock(&devpts_root->d_inode->i_mutex);
-
- return tty;
+ if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
+ return (struct tty_struct *)pts_inode->i_private;
+ return NULL;
}
-void devpts_pty_kill(int number)
+void devpts_pty_kill(struct tty_struct *tty)
{
- struct dentry *dentry = get_node(number);
+ struct inode *inode = tty->driver_data;
+ struct dentry *dentry;
- if (!IS_ERR(dentry)) {
- struct inode *inode = dentry->d_inode;
- if (inode) {
- inode->i_nlink--;
- d_delete(dentry);
- dput(dentry);
- }
+ BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
+
+ mutex_lock(&devpts_root->d_inode->i_mutex);
+
+ dentry = d_find_alias(inode);
+ if (dentry && !IS_ERR(dentry)) {
+ inode->i_nlink--;
+ d_delete(dentry);
dput(dentry);
}
+
mutex_unlock(&devpts_root->d_inode->i_mutex);
}
diff --git a/fs/dquot.c b/fs/dquot.c
index 8ec4d6cc763..ad7e59003e0 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -895,10 +895,9 @@ static void print_warning(struct dquot *dquot, const int warntype)
warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
return;
- mutex_lock(&tty_mutex);
tty = get_current_tty();
if (!tty)
- goto out_lock;
+ return;
tty_write_message(tty, dquot->dq_sb->s_id);
if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
tty_write_message(tty, ": warning, ");
@@ -926,8 +925,7 @@ static void print_warning(struct dquot *dquot, const int warntype)
break;
}
tty_write_message(tty, msg);
-out_lock:
- mutex_unlock(&tty_mutex);
+ tty_kref_put(tty);
}
#endif
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 448dfd597b5..8ebe9a5d1d9 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -211,7 +211,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
ecryptfs_opt_encrypted_view, ecryptfs_opt_err };
-static match_table_t tokens = {
+static const match_table_t tokens = {
{ecryptfs_opt_sig, "sig=%s"},
{ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
{ecryptfs_opt_cipher, "cipher=%s"},
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 567b134fa1f..73b19cfc91f 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -341,8 +341,6 @@ static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
sb->inode_blocks *
(EFS_BLOCKSIZE / sizeof(struct efs_dinode));
buf->f_ffree = sb->inode_free; /* free inodes */
- buf->f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
- buf->f_fsid.val[1] = sb->fs_magic & 0xffff; /* fs ID */
buf->f_namelen = EFS_MAXNAMELEN; /* max filename length */
return 0;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index fd88c7b43e6..647cd888ac8 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -393,7 +393,7 @@ enum {
Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_bsd_df, "bsddf"},
{Opt_minix_df, "minixdf"},
{Opt_grpid, "grpid"},
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index f38a5afc39a..399a96a6c55 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -760,7 +760,7 @@ enum {
Opt_grpquota
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_bsd_df, "bsddf"},
{Opt_minix_df, "minixdf"},
{Opt_grpid, "grpid"},
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index f46a513a515..6690a41cdd9 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -540,6 +540,8 @@ do { \
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
#define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */
#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
+#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
+
/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index ea27eaa0cfe..dc99b4776d5 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -192,7 +192,7 @@ setversion_out:
case EXT4_IOC_GROUP_EXTEND: {
ext4_fsblk_t n_blocks_count;
struct super_block *sb = inode->i_sb;
- int err;
+ int err, err2;
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
@@ -206,8 +206,10 @@ setversion_out:
err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
- jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+ err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+ if (err == 0)
+ err = err2;
mnt_drop_write(filp->f_path.mnt);
return err;
@@ -215,7 +217,7 @@ setversion_out:
case EXT4_IOC_GROUP_ADD: {
struct ext4_new_group_data input;
struct super_block *sb = inode->i_sb;
- int err;
+ int err, err2;
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
@@ -230,8 +232,10 @@ setversion_out:
err = ext4_group_add(sb, &input);
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
- jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+ err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+ if (err == 0)
+ err = err2;
mnt_drop_write(filp->f_path.mnt);
return err;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 0e661c56966..dea8f13c2fd 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -507,7 +507,8 @@ static void ext4_put_super(struct super_block *sb)
ext4_mb_release(sb);
ext4_ext_release(sb);
ext4_xattr_put_super(sb);
- jbd2_journal_destroy(sbi->s_journal);
+ if (jbd2_journal_destroy(sbi->s_journal) < 0)
+ ext4_abort(sb, __func__, "Couldn't clean up the journal");
sbi->s_journal = NULL;
if (!(sb->s_flags & MS_RDONLY)) {
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
@@ -777,6 +778,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_printf(seq, ",inode_readahead_blks=%u",
sbi->s_inode_readahead_blks);
+ if (test_opt(sb, DATA_ERR_ABORT))
+ seq_puts(seq, ",data_err=abort");
+
ext4_show_quota_options(seq, sb);
return 0;
}
@@ -906,6 +910,7 @@ enum {
Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
Opt_journal_checksum, Opt_journal_async_commit,
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+ Opt_data_err_abort, Opt_data_err_ignore,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
@@ -914,7 +919,7 @@ enum {
Opt_inode_readahead_blks
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_bsd_df, "bsddf"},
{Opt_minix_df, "minixdf"},
{Opt_grpid, "grpid"},
@@ -952,6 +957,8 @@ static match_table_t tokens = {
{Opt_data_journal, "data=journal"},
{Opt_data_ordered, "data=ordered"},
{Opt_data_writeback, "data=writeback"},
+ {Opt_data_err_abort, "data_err=abort"},
+ {Opt_data_err_ignore, "data_err=ignore"},
{Opt_offusrjquota, "usrjquota="},
{Opt_usrjquota, "usrjquota=%s"},
{Opt_offgrpjquota, "grpjquota="},
@@ -1186,6 +1193,12 @@ static int parse_options(char *options, struct super_block *sb,
sbi->s_mount_opt |= data_opt;
}
break;
+ case Opt_data_err_abort:
+ set_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+ break;
+ case Opt_data_err_ignore:
+ clear_opt(sbi->s_mount_opt, DATA_ERR_ABORT);
+ break;
#ifdef CONFIG_QUOTA
case Opt_usrjquota:
qtype = USRQUOTA;
@@ -2218,6 +2231,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount;
}
+#ifdef CONFIG_PROC_FS
if (ext4_proc_root)
sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
@@ -2225,6 +2239,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
proc_create_data("inode_readahead_blks", 0644, sbi->s_proc,
&ext4_ui_proc_fops,
&sbi->s_inode_readahead_blks);
+#endif
bgl_lock_init(&sbi->s_blockgroup_lock);
@@ -2534,6 +2549,10 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
journal->j_flags |= JBD2_BARRIER;
else
journal->j_flags &= ~JBD2_BARRIER;
+ if (test_opt(sb, DATA_ERR_ABORT))
+ journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
+ else
+ journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
spin_unlock(&journal->j_state_lock);
}
@@ -2853,7 +2872,9 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
journal_t *journal = EXT4_SB(sb)->s_journal;
jbd2_journal_lock_updates(journal);
- jbd2_journal_flush(journal);
+ if (jbd2_journal_flush(journal) < 0)
+ goto out;
+
lock_super(sb);
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
sb->s_flags & MS_RDONLY) {
@@ -2862,6 +2883,8 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
ext4_commit_super(sb, es, 1);
}
unlock_super(sb);
+
+out:
jbd2_journal_unlock_updates(journal);
}
@@ -2962,7 +2985,13 @@ static void ext4_write_super_lockfs(struct super_block *sb)
/* Now we set up the journal barrier. */
jbd2_journal_lock_updates(journal);
- jbd2_journal_flush(journal);
+
+ /*
+ * We don't want to clear needs_recovery flag when we failed
+ * to flush the journal.
+ */
+ if (jbd2_journal_flush(journal) < 0)
+ return;
/* Journal blocked and flushed, clear needs_recovery flag. */
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
@@ -3402,8 +3431,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
* otherwise be livelocked...
*/
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
- jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+ err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+ if (err) {
+ path_put(&nd.path);
+ return err;
+ }
}
err = vfs_quota_on_path(sb, type, format_id, &nd.path);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 80ff3381fa2..d12cdf2a040 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -855,7 +855,7 @@ enum {
Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err,
};
-static match_table_t fat_tokens = {
+static const match_table_t fat_tokens = {
{Opt_check_r, "check=relaxed"},
{Opt_check_s, "check=strict"},
{Opt_check_n, "check=normal"},
@@ -890,14 +890,14 @@ static match_table_t fat_tokens = {
{Opt_tz_utc, "tz=UTC"},
{Opt_err, NULL},
};
-static match_table_t msdos_tokens = {
+static const match_table_t msdos_tokens = {
{Opt_nodots, "nodots"},
{Opt_nodots, "dotsOK=no"},
{Opt_dots, "dots"},
{Opt_dots, "dotsOK=yes"},
{Opt_err, NULL}
};
-static match_table_t vfat_tokens = {
+static const match_table_t vfat_tokens = {
{Opt_charset, "iocharset=%s"},
{Opt_shortname_lower, "shortname=lower"},
{Opt_shortname_win95, "shortname=win95"},
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index d2249f174e2..6a84388cacf 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -354,7 +354,7 @@ enum {
OPT_ERR
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{OPT_FD, "fd=%u"},
{OPT_ROOTMODE, "rootmode=%o"},
{OPT_USER_ID, "user_id=%u"},
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index df48333e6f0..f96eb90a2cf 100644
--- a/fs/gfs2/mount.c
+++ b/fs/gfs2/mount.c
@@ -46,7 +46,7 @@ enum {
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_lockproto, "lockproto=%s"},
{Opt_locktable, "locktable=%s"},
{Opt_hostdata, "hostdata=%s"},
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 4abb1047c68..3c7c7637719 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -173,7 +173,7 @@ enum {
opt_err
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{ opt_uid, "uid=%u" },
{ opt_gid, "gid=%u" },
{ opt_umask, "umask=%o" },
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 9997cbf8beb..9699c56d323 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -25,7 +25,7 @@ enum {
opt_force, opt_err
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{ opt_creator, "creator=%s" },
{ opt_type, "type=%s" },
{ opt_umask, "umask=%o" },
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index b8ae9c90ada..29ad461d568 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -215,7 +215,7 @@ enum {
Opt_timeshift, Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_help, "help"},
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 3f58923fb39..61edc701b0e 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -57,7 +57,7 @@ enum {
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_size, "size=%s"},
{Opt_nr_inodes, "nr_inodes=%s"},
{Opt_mode, "mode=%o"},
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 33a6b7ecb8b..d152856c371 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -226,6 +226,8 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
return error;
}
+#ifdef CONFIG_BLOCK
+
#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
@@ -342,6 +344,8 @@ int generic_block_fiemap(struct inode *inode,
}
EXPORT_SYMBOL(generic_block_fiemap);
+#endif /* CONFIG_BLOCK */
+
static int file_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 26948a6033b..3f8af0f1505 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -310,7 +310,7 @@ enum {
Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_norock, "norock"},
{Opt_nojoliet, "nojoliet"},
{Opt_unhide, "unhide"},
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 42895d36945..9203c3332f1 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -94,7 +94,8 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
int ret = 0;
struct buffer_head *bh = jh2bh(jh);
- if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) {
+ if (jh->b_jlist == BJ_None && !buffer_locked(bh) &&
+ !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
JBUFFER_TRACE(jh, "remove from checkpoint list");
ret = __jbd2_journal_remove_checkpoint(jh) + 1;
jbd_unlock_bh_state(bh);
@@ -176,21 +177,25 @@ static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
* buffers. Note that we take the buffers in the opposite ordering
* from the one in which they were submitted for IO.
*
+ * Return 0 on success, and return <0 if some buffers have failed
+ * to be written out.
+ *
* Called with j_list_lock held.
*/
-static void __wait_cp_io(journal_t *journal, transaction_t *transaction)
+static int __wait_cp_io(journal_t *journal, transaction_t *transaction)
{
struct journal_head *jh;
struct buffer_head *bh;
tid_t this_tid;
int released = 0;
+ int ret = 0;
this_tid = transaction->t_tid;
restart:
/* Did somebody clean up the transaction in the meanwhile? */
if (journal->j_checkpoint_transactions != transaction ||
transaction->t_tid != this_tid)
- return;
+ return ret;
while (!released && transaction->t_checkpoint_io_list) {
jh = transaction->t_checkpoint_io_list;
bh = jh2bh(jh);
@@ -210,6 +215,9 @@ restart:
spin_lock(&journal->j_list_lock);
goto restart;
}
+ if (unlikely(buffer_write_io_error(bh)))
+ ret = -EIO;
+
/*
* Now in whatever state the buffer currently is, we know that
* it has been written out and so we can drop it from the list
@@ -219,6 +227,8 @@ restart:
jbd2_journal_remove_journal_head(bh);
__brelse(bh);
}
+
+ return ret;
}
#define NR_BATCH 64
@@ -242,7 +252,8 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
* Try to flush one buffer from the checkpoint list to disk.
*
* Return 1 if something happened which requires us to abort the current
- * scan of the checkpoint list.
+ * scan of the checkpoint list. Return <0 if the buffer has failed to
+ * be written out.
*
* Called with j_list_lock held and drops it if 1 is returned
* Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
@@ -274,6 +285,9 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
jbd2_log_wait_commit(journal, tid);
ret = 1;
} else if (!buffer_dirty(bh)) {
+ ret = 1;
+ if (unlikely(buffer_write_io_error(bh)))
+ ret = -EIO;
J_ASSERT_JH(jh, !buffer_jbddirty(bh));
BUFFER_TRACE(bh, "remove from checkpoint");
__jbd2_journal_remove_checkpoint(jh);
@@ -281,7 +295,6 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
jbd_unlock_bh_state(bh);
jbd2_journal_remove_journal_head(bh);
__brelse(bh);
- ret = 1;
} else {
/*
* Important: we are about to write the buffer, and
@@ -314,6 +327,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
* to disk. We submit larger chunks of data at once.
*
* The journal should be locked before calling this function.
+ * Called with j_checkpoint_mutex held.
*/
int jbd2_log_do_checkpoint(journal_t *journal)
{
@@ -339,6 +353,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
* OK, we need to start writing disk blocks. Take one transaction
* and write it.
*/
+ result = 0;
spin_lock(&journal->j_list_lock);
if (!journal->j_checkpoint_transactions)
goto out;
@@ -357,7 +372,7 @@ restart:
int batch_count = 0;
struct buffer_head *bhs[NR_BATCH];
struct journal_head *jh;
- int retry = 0;
+ int retry = 0, err;
while (!retry && transaction->t_checkpoint_list) {
struct buffer_head *bh;
@@ -371,6 +386,8 @@ restart:
}
retry = __process_buffer(journal, jh, bhs, &batch_count,
transaction);
+ if (retry < 0 && !result)
+ result = retry;
if (!retry && (need_resched() ||
spin_needbreak(&journal->j_list_lock))) {
spin_unlock(&journal->j_list_lock);
@@ -395,14 +412,18 @@ restart:
* Now we have cleaned up the first transaction's checkpoint
* list. Let's clean up the second one
*/
- __wait_cp_io(journal, transaction);
+ err = __wait_cp_io(journal, transaction);
+ if (!result)
+ result = err;
}
out:
spin_unlock(&journal->j_list_lock);
- result = jbd2_cleanup_journal_tail(journal);
if (result < 0)
- return result;
- return 0;
+ jbd2_journal_abort(journal, result);
+ else
+ result = jbd2_cleanup_journal_tail(journal);
+
+ return (result < 0) ? result : 0;
}
/*
@@ -418,8 +439,9 @@ out:
* This is the only part of the journaling code which really needs to be
* aware of transaction aborts. Checkpointing involves writing to the
* main filesystem area rather than to the journal, so it can proceed
- * even in abort state, but we must not update the journal superblock if
- * we have an abort error outstanding.
+ * even in abort state, but we must not update the super block if
+ * checkpointing may have failed. Otherwise, we would lose some metadata
+ * buffers which should be written-back to the filesystem.
*/
int jbd2_cleanup_journal_tail(journal_t *journal)
@@ -428,6 +450,9 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
tid_t first_tid;
unsigned long blocknr, freed;
+ if (is_journal_aborted(journal))
+ return 1;
+
/* OK, work out the oldest transaction remaining in the log, and
* the log block it starts at.
*
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 0d3814a35ed..0abe02c4242 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -504,9 +504,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
jh = commit_transaction->t_buffers;
/* If we're in abort mode, we just un-journal the buffer and
- release it for background writing. */
+ release it. */
if (is_journal_aborted(journal)) {
+ clear_buffer_jbddirty(jh2bh(jh));
JBUFFER_TRACE(jh, "journal is aborting: refile");
jbd2_journal_refile_buffer(journal, jh);
/* If that was the last one, we need to clean up
@@ -683,6 +684,8 @@ start_journal_io:
printk(KERN_WARNING
"JBD2: Detected IO errors while flushing file data "
"on %s\n", journal->j_devname);
+ if (journal->j_flags & JBD2_ABORT_ON_SYNCDATA_ERR)
+ jbd2_journal_abort(journal, err);
err = 0;
}
@@ -783,6 +786,9 @@ wait_for_iobuf:
/* AKPM: bforget here */
}
+ if (err)
+ jbd2_journal_abort(journal, err);
+
jbd_debug(3, "JBD: commit phase 5\n");
if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
@@ -881,6 +887,8 @@ restart_loop:
if (buffer_jbddirty(bh)) {
JBUFFER_TRACE(jh, "add to new checkpointing trans");
__jbd2_journal_insert_checkpoint(jh, commit_transaction);
+ if (is_journal_aborted(journal))
+ clear_buffer_jbddirty(bh);
JBUFFER_TRACE(jh, "refile for checkpoint writeback");
__jbd2_journal_refile_buffer(jh);
jbd_unlock_bh_state(bh);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 01c3901c3a0..783de118de9 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1451,9 +1451,12 @@ recovery_error:
*
* Release a journal_t structure once it is no longer in use by the
* journaled object.
+ * Return <0 if we couldn't clean up the journal.
*/
-void jbd2_journal_destroy(journal_t *journal)
+int jbd2_journal_destroy(journal_t *journal)
{
+ int err = 0;
+
/* Wait for the commit thread to wake up and die. */
journal_kill_thread(journal);
@@ -1476,11 +1479,16 @@ void jbd2_journal_destroy(journal_t *journal)
J_ASSERT(journal->j_checkpoint_transactions == NULL);
spin_unlock(&journal->j_list_lock);
- /* We can now mark the journal as empty. */
- journal->j_tail = 0;
- journal->j_tail_sequence = ++journal->j_transaction_sequence;
if (journal->j_sb_buffer) {
- jbd2_journal_update_superblock(journal, 1);
+ if (!is_journal_aborted(journal)) {
+ /* We can now mark the journal as empty. */
+ journal->j_tail = 0;
+ journal->j_tail_sequence =
+ ++journal->j_transaction_sequence;
+ jbd2_journal_update_superblock(journal, 1);
+ } else {
+ err = -EIO;
+ }
brelse(journal->j_sb_buffer);
}
@@ -1492,6 +1500,8 @@ void jbd2_journal_destroy(journal_t *journal)
jbd2_journal_destroy_revoke(journal);
kfree(journal->j_wbuf);
kfree(journal);
+
+ return err;
}
@@ -1717,10 +1727,16 @@ int jbd2_journal_flush(journal_t *journal)
spin_lock(&journal->j_list_lock);
while (!err && journal->j_checkpoint_transactions != NULL) {
spin_unlock(&journal->j_list_lock);
+ mutex_lock(&journal->j_checkpoint_mutex);
err = jbd2_log_do_checkpoint(journal);
+ mutex_unlock(&journal->j_checkpoint_mutex);
spin_lock(&journal->j_list_lock);
}
spin_unlock(&journal->j_list_lock);
+
+ if (is_journal_aborted(journal))
+ return -EIO;
+
jbd2_cleanup_journal_tail(journal);
/* Finally, mark the journal as really needing no recovery.
@@ -1742,7 +1758,7 @@ int jbd2_journal_flush(journal_t *journal)
J_ASSERT(journal->j_head == journal->j_tail);
J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
spin_unlock(&journal->j_state_lock);
- return err;
+ return 0;
}
/**
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 058f50f65b7..73063285b13 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -225,7 +225,7 @@ do { \
*/
int jbd2_journal_recover(journal_t *journal)
{
- int err;
+ int err, err2;
journal_superblock_t * sb;
struct recovery_info info;
@@ -263,7 +263,10 @@ int jbd2_journal_recover(journal_t *journal)
journal->j_transaction_sequence = ++info.end_transaction;
jbd2_journal_clear_revoke(journal);
- sync_blockdev(journal->j_fs_dev);
+ err2 = sync_blockdev(journal->j_fs_dev);
+ if (!err)
+ err = err2;
+
return err;
}
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 3630718be39..0dae345e481 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -199,7 +199,7 @@ enum {
Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_integrity, "integrity"},
{Opt_nointegrity, "nointegrity"},
{Opt_iocharset, "iocharset=%s"},
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 46763d1cd39..8478fc25dae 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -127,7 +127,7 @@ enum {
Opt_err
};
-static match_table_t __initdata tokens = {
+static match_table_t __initconst tokens = {
{Opt_port, "port=%u"},
{Opt_rsize, "rsize=%u"},
{Opt_wsize, "wsize=%u"},
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index e9b20173fef..ffb697416cb 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -98,7 +98,7 @@ enum {
Opt_err
};
-static match_table_t nfs_mount_option_tokens = {
+static const match_table_t nfs_mount_option_tokens = {
{ Opt_userspace, "bg" },
{ Opt_userspace, "fg" },
{ Opt_userspace, "retry=%s" },
@@ -163,7 +163,7 @@ enum {
Opt_xprt_err
};
-static match_table_t nfs_xprt_protocol_tokens = {
+static const match_table_t nfs_xprt_protocol_tokens = {
{ Opt_xprt_udp, "udp" },
{ Opt_xprt_tcp, "tcp" },
{ Opt_xprt_rdma, "rdma" },
@@ -180,7 +180,7 @@ enum {
Opt_sec_err
};
-static match_table_t nfs_secflavor_tokens = {
+static const match_table_t nfs_secflavor_tokens = {
{ Opt_sec_none, "none" },
{ Opt_sec_none, "null" },
{ Opt_sec_sys, "sys" },
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 88255d3f52b..70334d85aff 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -157,7 +157,7 @@ enum {
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_barrier, "barrier=%u"},
{Opt_err_panic, "errors=panic"},
{Opt_err_ro, "errors=remount-ro"},
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index d29047b1b9b..cbf047a847c 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -346,7 +346,7 @@ enum {
Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{Opt_umask, "umask=%o"},
diff --git a/fs/open.c b/fs/open.c
index 07da9359481..5596049863b 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1141,8 +1141,7 @@ EXPORT_SYMBOL(sys_close);
asmlinkage long sys_vhangup(void)
{
if (capable(CAP_SYS_TTY_CONFIG)) {
- /* XXX: this needs locking */
- tty_vhangup(current->signal->tty);
+ tty_vhangup_self();
return 0;
}
return -EPERM;
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 73cd7a418f0..50f8f0600f0 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -57,3 +57,13 @@ config PROC_SYSCTL
As it is generally a good thing, you should say Y here unless
building a kernel for install/rescue disks or your system is very
limited in memory.
+
+config PROC_PAGE_MONITOR
+ default y
+ depends on PROC_FS && MMU
+ bool "Enable /proc page monitoring" if EMBEDDED
+ help
+ Various /proc files exist to monitor process memory utilization:
+ /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+ /proc/kpagecount, and /proc/kpageflags. Disabling these
+ interfaces will reduce the size of the kernel by approximately 4kb.
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 71c9be59c9c..f4bc0e78953 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -86,11 +86,6 @@
#include <asm/processor.h>
#include "internal.h"
-/* Gcc optimizes away "strlen(x)" for constant x */
-#define ADDBUF(buffer, string) \
-do { memcpy(buffer, string, strlen(string)); \
- buffer += strlen(string); } while (0)
-
static inline void task_name(struct seq_file *m, struct task_struct *p)
{
int i;
@@ -261,7 +256,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
sigemptyset(&ignored);
sigemptyset(&caught);
- rcu_read_lock();
if (lock_task_sighand(p, &flags)) {
pending = p->pending.signal;
shpending = p->signal->shared_pending.signal;
@@ -272,7 +266,6 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
unlock_task_sighand(p, &flags);
}
- rcu_read_unlock();
seq_printf(m, "Threads:\t%d\n", num_threads);
seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a28840b11b8..b5918ae8ca7 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -148,9 +148,6 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
return count;
}
-int maps_protect;
-EXPORT_SYMBOL(maps_protect);
-
static struct fs_struct *get_fs_struct(struct task_struct *task)
{
struct fs_struct *fs;
@@ -164,7 +161,6 @@ static struct fs_struct *get_fs_struct(struct task_struct *task)
static int get_nr_threads(struct task_struct *tsk)
{
- /* Must be called with the rcu_read_lock held */
unsigned long flags;
int count = 0;
@@ -471,14 +467,10 @@ static int proc_pid_limits(struct task_struct *task, char *buffer)
struct rlimit rlim[RLIM_NLIMITS];
- rcu_read_lock();
- if (!lock_task_sighand(task,&flags)) {
- rcu_read_unlock();
+ if (!lock_task_sighand(task, &flags))
return 0;
- }
memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS);
unlock_task_sighand(task, &flags);
- rcu_read_unlock();
/*
* print the file header
@@ -2443,6 +2435,13 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)
}
#endif /* CONFIG_TASK_IO_ACCOUNTING */
+static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
+ struct pid *pid, struct task_struct *task)
+{
+ seq_printf(m, "%08x\n", task->personality);
+ return 0;
+}
+
/*
* Thread groups
*/
@@ -2459,6 +2458,7 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("environ", S_IRUSR, environ),
INF("auxv", S_IRUSR, pid_auxv),
ONE("status", S_IRUGO, pid_status),
+ ONE("personality", S_IRUSR, pid_personality),
INF("limits", S_IRUSR, pid_limits),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, pid_sched),
@@ -2794,6 +2794,7 @@ static const struct pid_entry tid_base_stuff[] = {
REG("environ", S_IRUSR, environ),
INF("auxv", S_IRUSR, pid_auxv),
ONE("status", S_IRUGO, pid_status),
+ ONE("personality", S_IRUSR, pid_personality),
INF("limits", S_IRUSR, pid_limits),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, pid_sched),
@@ -3088,9 +3089,7 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
generic_fillattr(inode, stat);
if (p) {
- rcu_read_lock();
stat->nlink += get_nr_threads(p);
- rcu_read_unlock();
put_task_struct(p);
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 8bb03f056c2..c6b4fa7e3b4 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -342,7 +342,7 @@ static int proc_reg_open(struct inode *inode, struct file *file)
if (!pde->proc_fops) {
spin_unlock(&pde->pde_unload_lock);
kfree(pdeo);
- return rv;
+ return -EINVAL;
}
pde->pde_users++;
open = pde->proc_fops->open;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 442202314d5..3bfb7b8747b 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -45,8 +45,6 @@ do { \
extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
#endif
-extern int maps_protect;
-
extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task);
extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 29e20c6b1f7..66c1ab87656 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -68,7 +68,6 @@
extern int get_hardware_list(char *);
extern int get_stram_list(char *);
extern int get_exec_domain_list(char *);
-extern int get_dma_list(char *);
static int proc_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index f9a8b892718..945a81043ba 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -66,7 +66,7 @@ static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
return NULL;
}
-struct ctl_table_header *grab_header(struct inode *inode)
+static struct ctl_table_header *grab_header(struct inode *inode)
{
if (PROC_I(inode)->sysctl)
return sysctl_head_grab(PROC_I(inode)->sysctl);
@@ -395,10 +395,10 @@ static struct dentry_operations proc_sys_dentry_operations = {
.d_compare = proc_sys_compare,
};
-static struct proc_dir_entry *proc_sys_root;
-
int proc_sys_init(void)
{
+ struct proc_dir_entry *proc_sys_root;
+
proc_sys_root = proc_mkdir("sys", NULL);
proc_sys_root->proc_iops = &proc_sys_dir_operations;
proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 73d1891ee62..4806830ea2a 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -210,9 +210,6 @@ static int show_map(struct seq_file *m, void *v)
dev_t dev = 0;
int len;
- if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
- return -EACCES;
-
if (file) {
struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
dev = inode->i_sb->s_dev;
@@ -742,22 +739,11 @@ const struct file_operations proc_pagemap_operations = {
#ifdef CONFIG_NUMA
extern int show_numa_map(struct seq_file *m, void *v);
-static int show_numa_map_checked(struct seq_file *m, void *v)
-{
- struct proc_maps_private *priv = m->private;
- struct task_struct *task = priv->task;
-
- if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
- return -EACCES;
-
- return show_numa_map(m, v);
-}
-
static const struct seq_operations proc_pid_numa_maps_op = {
.start = m_start,
.next = m_next,
.stop = m_stop,
- .show = show_numa_map_checked
+ .show = show_numa_map,
};
static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 5d84e7121df..219bd79ea89 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -110,11 +110,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
static int show_map(struct seq_file *m, void *_vml)
{
struct vm_list_struct *vml = _vml;
- struct proc_maps_private *priv = m->private;
- struct task_struct *task = priv->task;
-
- if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
- return -EACCES;
return nommu_vma_show(m, vml->vma);
}
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 9ac0f5e064e..841368b87a2 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -165,14 +165,8 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
return acc;
}
-static int open_vmcore(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
const struct file_operations proc_vmcore_operations = {
.read = read_vmcore,
- .open = open_vmcore,
};
static struct vmcore* __init get_new_element(void)
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 3f4902060c7..9a9220333b3 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -848,7 +848,7 @@ enum {
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_fast_unmount, "fast_unmount"},
{Opt_norm_unmount, "norm_unmount"},
{Opt_err, NULL},
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 5698bbf83bb..e25e7010627 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -369,7 +369,7 @@ enum {
Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_novrs, "novrs"},
{Opt_nostrict, "nostrict"},
{Opt_bs, "bs=%u"},
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 3141969b456..e65212dfb60 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -309,7 +309,7 @@ enum {
Opt_err
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_type_old, "ufstype=old"},
{Opt_type_sunx86, "ufstype=sunx86"},
{Opt_type_sun, "ufstype=sun"},
@@ -1233,7 +1233,7 @@ static int ufs_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb);
unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;
- struct match_token *tp = tokens;
+ const struct match_token *tp = tokens;
while (tp->token != Opt_onerror_panic && tp->token != mval)
++tp;
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 18d3c848783..7227b2efef2 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -158,7 +158,7 @@ enum {
Opt_barrier, Opt_nobarrier, Opt_err
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_barrier, "barrier"},
{Opt_nobarrier, "nobarrier"},
{Opt_err, NULL}
diff --git a/include/asm-cris/a.out.h b/include/asm-cris/a.out.h
deleted file mode 100644
index c82e9f9b75f..00000000000
--- a/include/asm-cris/a.out.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __CRIS_A_OUT_H__
-#define __CRIS_A_OUT_H__
-
-/* we don't support a.out binaries on Linux/CRIS anyway, so this is
- * not really used but still needed because binfmt_elf.c for some reason
- * wants to know about a.out even if there is no interpreter available...
- */
-
-struct exec
-{
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif
diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
index 8786e01e0db..969570167e9 100644
--- a/include/asm-generic/siginfo.h
+++ b/include/asm-generic/siginfo.h
@@ -199,6 +199,8 @@ typedef struct siginfo {
*/
#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */
#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */
+#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
+#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint/watchpoint */
#define NSIGTRAP 2
/*
diff --git a/include/asm-generic/statfs.h b/include/asm-generic/statfs.h
index 1d01043e797..6129d680214 100644
--- a/include/asm-generic/statfs.h
+++ b/include/asm-generic/statfs.h
@@ -6,33 +6,64 @@
typedef __kernel_fsid_t fsid_t;
#endif
+/*
+ * Most 64-bit platforms use 'long', while most 32-bit platforms use '__u32'.
+ * Yes, they differ in signedness as well as size.
+ * Special cases can override it for themselves -- except for S390x, which
+ * is just a little too special for us. And MIPS, which I'm not touching
+ * with a 10' pole.
+ */
+#ifndef __statfs_word
+#if BITS_PER_LONG == 64
+#define __statfs_word long
+#else
+#define __statfs_word __u32
+#endif
+#endif
+
struct statfs {
- __u32 f_type;
- __u32 f_bsize;
- __u32 f_blocks;
- __u32 f_bfree;
- __u32 f_bavail;
- __u32 f_files;
- __u32 f_ffree;
+ __statfs_word f_type;
+ __statfs_word f_bsize;
+ __statfs_word f_blocks;
+ __statfs_word f_bfree;
+ __statfs_word f_bavail;
+ __statfs_word f_files;
+ __statfs_word f_ffree;
__kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
+ __statfs_word f_namelen;
+ __statfs_word f_frsize;
+ __statfs_word f_spare[5];
};
+/*
+ * ARM needs to avoid the 32-bit padding at the end, for consistency
+ * between EABI and OABI
+ */
+#ifndef ARCH_PACK_STATFS64
+#define ARCH_PACK_STATFS64
+#endif
+
struct statfs64 {
- __u32 f_type;
- __u32 f_bsize;
+ __statfs_word f_type;
+ __statfs_word f_bsize;
__u64 f_blocks;
__u64 f_bfree;
__u64 f_bavail;
__u64 f_files;
__u64 f_ffree;
__kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-};
+ __statfs_word f_namelen;
+ __statfs_word f_frsize;
+ __statfs_word f_spare[5];
+} ARCH_PACK_STATFS64;
+
+/*
+ * IA64 and x86_64 need to avoid the 32-bit padding at the end,
+ * to be compatible with the i386 ABI
+ */
+#ifndef ARCH_PACK_COMPAT_STATFS64
+#define ARCH_PACK_COMPAT_STATFS64
+#endif
struct compat_statfs64 {
__u32 f_type;
@@ -46,6 +77,6 @@ struct compat_statfs64 {
__u32 f_namelen;
__u32 f_frsize;
__u32 f_spare[5];
-};
+} ARCH_PACK_COMPAT_STATFS64;
#endif
diff --git a/include/asm-m32r/a.out.h b/include/asm-m32r/a.out.h
deleted file mode 100644
index ab150f5c166..00000000000
--- a/include/asm-m32r/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_M32R_A_OUT_H
-#define _ASM_M32R_A_OUT_H
-
-struct exec
-{
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif /* _ASM_M32R_A_OUT_H */
diff --git a/include/asm-parisc/a.out.h b/include/asm-parisc/a.out.h
deleted file mode 100644
index eb04e34c5bb..00000000000
--- a/include/asm-parisc/a.out.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __PARISC_A_OUT_H__
-#define __PARISC_A_OUT_H__
-
-struct exec
-{
- unsigned int a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#define N_TRSIZE(a) ((a).a_trsize)
-#define N_DRSIZE(a) ((a).a_drsize)
-#define N_SYMSIZE(a) ((a).a_syms)
-
-#endif /* __A_OUT_GNU_H__ */
diff --git a/include/asm-parisc/siginfo.h b/include/asm-parisc/siginfo.h
index d4909f55fe3..d7034728f37 100644
--- a/include/asm-parisc/siginfo.h
+++ b/include/asm-parisc/siginfo.h
@@ -3,11 +3,6 @@
#include <asm-generic/siginfo.h>
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */
-#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */
#undef NSIGTRAP
#define NSIGTRAP 4
diff --git a/include/asm-parisc/statfs.h b/include/asm-parisc/statfs.h
index 1d2b8130b23..324bea905dc 100644
--- a/include/asm-parisc/statfs.h
+++ b/include/asm-parisc/statfs.h
@@ -1,58 +1,7 @@
#ifndef _PARISC_STATFS_H
#define _PARISC_STATFS_H
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t fsid_t;
-
-#endif
-
-/*
- * It appears that PARISC could be 64 _or_ 32 bit.
- * 64-bit fields must be explicitly 64-bit in statfs64.
- */
-struct statfs {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-
-struct statfs64 {
- long f_type;
- long f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-
-struct compat_statfs64 {
- __u32 f_type;
- __u32 f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-};
+#define __statfs_word long
+#include <asm-generic/statfs.h>
#endif
diff --git a/include/asm-x86/bios_ebda.h b/include/asm-x86/bios_ebda.h
index ec42ed87459..79b4b88505d 100644
--- a/include/asm-x86/bios_ebda.h
+++ b/include/asm-x86/bios_ebda.h
@@ -16,4 +16,21 @@ static inline unsigned int get_bios_ebda(void)
void reserve_ebda_region(void);
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+/*
+ * This is obviously not a great place for this, but we want to be
+ * able to scatter it around anywhere in the kernel.
+ */
+void check_for_bios_corruption(void);
+void start_periodic_check_for_corruption(void);
+#else
+static inline void check_for_bios_corruption(void)
+{
+}
+
+static inline void start_periodic_check_for_corruption(void)
+{
+}
+#endif
+
#endif /* ASM_X86__BIOS_EBDA_H */
diff --git a/include/asm-x86/boot.h b/include/asm-x86/boot.h
index 825de5dc867..1d63bd5d594 100644
--- a/include/asm-x86/boot.h
+++ b/include/asm-x86/boot.h
@@ -2,9 +2,7 @@
#define ASM_X86__BOOT_H
/* Don't touch these, unless you really know what you're doing. */
-#define DEF_INITSEG 0x9000
#define DEF_SYSSEG 0x1000
-#define DEF_SETUPSEG 0x9020
#define DEF_SYSSIZE 0x7F00
/* Internal svga startup constants */
diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h
index b73fea54def..f06adac7938 100644
--- a/include/asm-x86/desc.h
+++ b/include/asm-x86/desc.h
@@ -24,6 +24,11 @@ static inline void fill_ldt(struct desc_struct *desc,
desc->d = info->seg_32bit;
desc->g = info->limit_in_pages;
desc->base2 = (info->base_addr & 0xff000000) >> 24;
+ /*
+ * Don't allow setting of the lm bit. It is useless anyway
+ * because 64bit system calls require __USER_CS:
+ */
+ desc->l = 0;
}
extern struct desc_ptr idt_descr;
@@ -97,7 +102,15 @@ static inline int desc_empty(const void *ptr)
native_write_gdt_entry(dt, entry, desc, type)
#define write_idt_entry(dt, entry, g) \
native_write_idt_entry(dt, entry, g)
-#endif
+
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+#endif /* CONFIG_PARAVIRT */
static inline void native_write_idt_entry(gate_desc *idt, int entry,
const gate_desc *gate)
@@ -338,20 +351,16 @@ static inline void set_system_intr_gate(unsigned int n, void *addr)
_set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
}
-static inline void set_trap_gate(unsigned int n, void *addr)
+static inline void set_system_trap_gate(unsigned int n, void *addr)
{
BUG_ON((unsigned)n > 0xFF);
- _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS);
+ _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
}
-static inline void set_system_gate(unsigned int n, void *addr)
+static inline void set_trap_gate(unsigned int n, void *addr)
{
BUG_ON((unsigned)n > 0xFF);
-#ifdef CONFIG_X86_32
- _set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
-#else
- _set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);
-#endif
+ _set_gate(n, GATE_TRAP, addr, 0, 0, __KERNEL_CS);
}
static inline void set_task_gate(unsigned int n, unsigned int gdt_entry)
@@ -366,7 +375,7 @@ static inline void set_intr_gate_ist(int n, void *addr, unsigned ist)
_set_gate(n, GATE_INTERRUPT, addr, 0, ist, __KERNEL_CS);
}
-static inline void set_system_gate_ist(int n, void *addr, unsigned ist)
+static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist)
{
BUG_ON((unsigned)n > 0xFF);
_set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS);
diff --git a/include/asm-x86/es7000/mpparse.h b/include/asm-x86/es7000/mpparse.h
index 7b5c889d8e7..ed5a3caae14 100644
--- a/include/asm-x86/es7000/mpparse.h
+++ b/include/asm-x86/es7000/mpparse.h
@@ -5,6 +5,7 @@
extern int parse_unisys_oem (char *oemptr);
extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
+extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
extern void setup_unisys(void);
#ifndef CONFIG_X86_GENERICARCH
diff --git a/include/asm-x86/fixmap_32.h b/include/asm-x86/fixmap_32.h
index 784e3e75986..8844002da0e 100644
--- a/include/asm-x86/fixmap_32.h
+++ b/include/asm-x86/fixmap_32.h
@@ -94,10 +94,10 @@ enum fixed_addresses {
* can have a single pgd entry and a single pte table:
*/
#define NR_FIX_BTMAPS 64
-#define FIX_BTMAPS_NESTING 4
+#define FIX_BTMAPS_SLOTS 4
FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
(__end_of_permanent_fixed_addresses & 255),
- FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+ FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
FIX_WP_TEST,
#ifdef CONFIG_ACPI
FIX_ACPI_BEGIN,
diff --git a/include/asm-x86/fixmap_64.h b/include/asm-x86/fixmap_64.h
index dafb24bc042..dab4751d130 100644
--- a/include/asm-x86/fixmap_64.h
+++ b/include/asm-x86/fixmap_64.h
@@ -49,6 +49,7 @@ enum fixed_addresses {
#ifdef CONFIG_PARAVIRT
FIX_PARAVIRT_BOOTMAP,
#endif
+ __end_of_permanent_fixed_addresses,
#ifdef CONFIG_ACPI
FIX_ACPI_BEGIN,
FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
@@ -56,19 +57,18 @@ enum fixed_addresses {
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
FIX_OHCI1394_BASE,
#endif
- __end_of_permanent_fixed_addresses,
/*
* 256 temporary boot-time mappings, used by early_ioremap(),
* before ioremap() is functional.
*
- * We round it up to the next 512 pages boundary so that we
+ * We round it up to the next 256 pages boundary so that we
* can have a single pgd entry and a single pte table:
*/
#define NR_FIX_BTMAPS 64
-#define FIX_BTMAPS_NESTING 4
- FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 -
- (__end_of_permanent_fixed_addresses & 511),
- FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
+#define FIX_BTMAPS_SLOTS 4
+ FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
+ (__end_of_permanent_fixed_addresses & 255),
+ FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
__end_of_fixed_addresses
};
diff --git a/include/asm-x86/io.h b/include/asm-x86/io.h
index 72b7719523b..a233f835e0b 100644
--- a/include/asm-x86/io.h
+++ b/include/asm-x86/io.h
@@ -5,20 +5,6 @@
#include <linux/compiler.h>
-/*
- * early_ioremap() and early_iounmap() are for temporary early boot-time
- * mappings, before the real ioremap() is functional.
- * A boot-time mapping is currently limited to at most 16 pages.
- */
-#ifndef __ASSEMBLY__
-extern void early_ioremap_init(void);
-extern void early_ioremap_clear(void);
-extern void early_ioremap_reset(void);
-extern void *early_ioremap(unsigned long offset, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
-#endif
-
#define build_mmio_read(name, size, type, reg, barrier) \
static inline type name(const volatile void __iomem *addr) \
{ type ret; asm volatile("mov" size " %1,%0":reg (ret) \
@@ -97,6 +83,7 @@ extern void early_ioremap_init(void);
extern void early_ioremap_clear(void);
extern void early_ioremap_reset(void);
extern void *early_ioremap(unsigned long offset, unsigned long size);
+extern void *early_memremap(unsigned long offset, unsigned long size);
extern void early_iounmap(void *addr, unsigned long size);
extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index 64429e9431a..ee6e086b7df 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -165,9 +165,6 @@ static inline void *phys_to_virt(unsigned long address)
#include <asm-generic/iomap.h>
-extern void *early_ioremap(unsigned long addr, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-
/*
* This one maps high address device memory and turns off caching for that area.
* it's useful if some control registers are in such an area and write combining
diff --git a/include/asm-x86/ioctls.h b/include/asm-x86/ioctls.h
index 33660351239..06752a64904 100644
--- a/include/asm-x86/ioctls.h
+++ b/include/asm-x86/ioctls.h
@@ -51,9 +51,15 @@
#define TCSETS2 _IOW('T', 0x2B, struct termios2)
#define TCSETSW2 _IOW('T', 0x2C, struct termios2)
#define TCSETSF2 _IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485 0x542E
+#define TIOCSRS485 0x542F
#define TIOCGPTN _IOR('T', 0x30, unsigned int)
/* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */
+#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX 0x5433
+#define TCSETXF 0x5434
+#define TCSETXW 0x5435
#define FIONCLEX 0x5450
#define FIOCLEX 0x5451
diff --git a/include/asm-x86/irqflags.h b/include/asm-x86/irqflags.h
index 424acb48cd6..2bdab21f089 100644
--- a/include/asm-x86/irqflags.h
+++ b/include/asm-x86/irqflags.h
@@ -166,27 +166,6 @@ static inline int raw_irqs_disabled(void)
return raw_irqs_disabled_flags(flags);
}
-/*
- * makes the traced hardirq state match with the machine state
- *
- * should be a rarely used function, only in places where its
- * otherwise impossible to know the irq state, like in traps.
- */
-static inline void trace_hardirqs_fixup_flags(unsigned long flags)
-{
- if (raw_irqs_disabled_flags(flags))
- trace_hardirqs_off();
- else
- trace_hardirqs_on();
-}
-
-static inline void trace_hardirqs_fixup(void)
-{
- unsigned long flags = __raw_local_save_flags();
-
- trace_hardirqs_fixup_flags(flags);
-}
-
#else
#ifdef CONFIG_X86_64
diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h
index 5ec3ad3e825..fbbab66ee9d 100644
--- a/include/asm-x86/kdebug.h
+++ b/include/asm-x86/kdebug.h
@@ -27,10 +27,9 @@ extern void printk_address(unsigned long address, int reliable);
extern void die(const char *, struct pt_regs *,long);
extern int __must_check __die(const char *, struct pt_regs *, long);
extern void show_registers(struct pt_regs *regs);
-extern void __show_registers(struct pt_regs *, int all);
extern void show_trace(struct task_struct *t, struct pt_regs *regs,
unsigned long *sp, unsigned long bp);
-extern void __show_regs(struct pt_regs *regs);
+extern void __show_regs(struct pt_regs *regs, int all);
extern void show_regs(struct pt_regs *regs);
extern unsigned long oops_begin(void);
extern void oops_end(unsigned long, struct pt_regs *, int signr);
diff --git a/include/asm-x86/kprobes.h b/include/asm-x86/kprobes.h
index bd8407863c1..8a0748d0103 100644
--- a/include/asm-x86/kprobes.h
+++ b/include/asm-x86/kprobes.h
@@ -82,15 +82,6 @@ struct kprobe_ctlblk {
struct prev_kprobe prev_kprobe;
};
-/* trap3/1 are intr gates for kprobes. So, restore the status of IF,
- * if necessary, before executing the original int3/1 (trap) handler.
- */
-static inline void restore_interrupts(struct pt_regs *regs)
-{
- if (regs->flags & X86_EFLAGS_IF)
- local_irq_enable();
-}
-
extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
diff --git a/include/asm-x86/mach-default/mach_traps.h b/include/asm-x86/mach-default/mach_traps.h
index de9ac3f5c4c..ff8778f26b8 100644
--- a/include/asm-x86/mach-default/mach_traps.h
+++ b/include/asm-x86/mach-default/mach_traps.h
@@ -7,12 +7,6 @@
#include <asm/mc146818rtc.h>
-static inline void clear_mem_error(unsigned char reason)
-{
- reason = (reason & 0xf) | 4;
- outb(reason, 0x61);
-}
-
static inline unsigned char get_nmi_reason(void)
{
return inb(0x61);
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h
new file mode 100644
index 00000000000..62c793bb70c
--- /dev/null
+++ b/include/asm-x86/microcode.h
@@ -0,0 +1,47 @@
+#ifndef ASM_X86__MICROCODE_H
+#define ASM_X86__MICROCODE_H
+
+struct cpu_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int rev;
+};
+
+struct device;
+
+struct microcode_ops {
+ int (*request_microcode_user) (int cpu, const void __user *buf, size_t size);
+ int (*request_microcode_fw) (int cpu, struct device *device);
+
+ void (*apply_microcode) (int cpu);
+
+ int (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
+ void (*microcode_fini_cpu) (int cpu);
+};
+
+struct ucode_cpu_info {
+ struct cpu_signature cpu_sig;
+ int valid;
+ void *mc;
+};
+extern struct ucode_cpu_info ucode_cpu_info[];
+
+#ifdef CONFIG_MICROCODE_INTEL
+extern struct microcode_ops * __init init_intel_microcode(void);
+#else
+static inline struct microcode_ops * __init init_intel_microcode(void)
+{
+ return NULL;
+}
+#endif /* CONFIG_MICROCODE_INTEL */
+
+#ifdef CONFIG_MICROCODE_AMD
+extern struct microcode_ops * __init init_amd_microcode(void);
+#else
+static inline struct microcode_ops * __init init_amd_microcode(void)
+{
+ return NULL;
+}
+#endif
+
+#endif /* ASM_X86__MICROCODE_H */
diff --git a/include/asm-x86/mmzone_64.h b/include/asm-x86/mmzone_64.h
index 626b03a1487..6480f3333b2 100644
--- a/include/asm-x86/mmzone_64.h
+++ b/include/asm-x86/mmzone_64.h
@@ -7,7 +7,7 @@
#ifdef CONFIG_NUMA
-#define VIRTUAL_BUG_ON(x)
+#include <linux/mmdebug.h>
#include <asm/smp.h>
@@ -29,7 +29,6 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
{
unsigned nid;
VIRTUAL_BUG_ON(!memnodemap);
- VIRTUAL_BUG_ON((addr >> memnode_shift) >= memnodemapsize);
nid = memnodemap[addr >> memnode_shift];
VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
return nid;
diff --git a/include/asm-x86/module.h b/include/asm-x86/module.h
index 48dc3e0c07d..864f2005fc1 100644
--- a/include/asm-x86/module.h
+++ b/include/asm-x86/module.h
@@ -52,8 +52,6 @@ struct mod_arch_specific {};
#define MODULE_PROC_FAMILY "EFFICEON "
#elif defined CONFIG_MWINCHIPC6
#define MODULE_PROC_FAMILY "WINCHIPC6 "
-#elif defined CONFIG_MWINCHIP2
-#define MODULE_PROC_FAMILY "WINCHIP2 "
#elif defined CONFIG_MWINCHIP3D
#define MODULE_PROC_FAMILY "WINCHIP3D "
#elif defined CONFIG_MCYRIXIII
diff --git a/include/asm-x86/nmi.h b/include/asm-x86/nmi.h
index d5e715f024d..a53f829a97c 100644
--- a/include/asm-x86/nmi.h
+++ b/include/asm-x86/nmi.h
@@ -15,10 +15,6 @@
*/
int do_nmi_callback(struct pt_regs *regs, int cpu);
-#ifdef CONFIG_X86_64
-extern void default_do_nmi(struct pt_regs *);
-#endif
-
extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
extern int check_nmi_watchdog(void);
extern int nmi_watchdog_enabled;
diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h
index c9157477675..d4f1d5791fc 100644
--- a/include/asm-x86/page.h
+++ b/include/asm-x86/page.h
@@ -179,6 +179,7 @@ static inline pteval_t native_pte_flags(pte_t pte)
#endif /* CONFIG_PARAVIRT */
#define __pa(x) __phys_addr((unsigned long)(x))
+#define __pa_nodebug(x) __phys_addr_nodebug((unsigned long)(x))
/* __pa_symbol should be used for C visible symbols.
This seems to be the official gcc blessed way to do such arithmetic. */
#define __pa_symbol(x) __pa(__phys_reloc_hide((unsigned long)(x)))
@@ -188,9 +189,14 @@ static inline pteval_t native_pte_flags(pte_t pte)
#define __boot_va(x) __va(x)
#define __boot_pa(x) __pa(x)
+/*
+ * virt_to_page(kaddr) returns a valid pointer if and only if
+ * virt_addr_valid(kaddr) returns true.
+ */
#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)
+extern bool __virt_addr_valid(unsigned long kaddr);
+#define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr))
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-x86/page_32.h b/include/asm-x86/page_32.h
index 72f7305682c..e8d80d1de23 100644
--- a/include/asm-x86/page_32.h
+++ b/include/asm-x86/page_32.h
@@ -20,6 +20,12 @@
#endif
#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+#define STACKFAULT_STACK 0
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 0
+#define DEBUG_STACK 0
+#define MCE_STACK 0
+#define N_EXCEPTION_STACKS 1
#ifdef CONFIG_X86_PAE
/* 44=32+12, the limit we can fit into an unsigned long pfn */
@@ -73,7 +79,12 @@ typedef struct page *pgtable_t;
#endif
#ifndef __ASSEMBLY__
-#define __phys_addr(x) ((x) - PAGE_OFFSET)
+#define __phys_addr_nodebug(x) ((x) - PAGE_OFFSET)
+#ifdef CONFIG_DEBUG_VIRTUAL
+extern unsigned long __phys_addr(unsigned long);
+#else
+#define __phys_addr(x) __phys_addr_nodebug(x)
+#endif
#define __phys_reloc_hide(x) RELOC_HIDE((x), 0)
#ifdef CONFIG_FLATMEM
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h
index d7d358a4399..8d6ae2f760d 100644
--- a/include/asm-x86/paravirt.h
+++ b/include/asm-x86/paravirt.h
@@ -124,6 +124,9 @@ struct pv_cpu_ops {
int entrynum, const void *desc, int size);
void (*write_idt_entry)(gate_desc *,
int entrynum, const gate_desc *gate);
+ void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
+ void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
+
void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
void (*set_iopl_mask)(unsigned mask);
@@ -325,6 +328,7 @@ struct pv_lock_ops {
int (*spin_is_locked)(struct raw_spinlock *lock);
int (*spin_is_contended)(struct raw_spinlock *lock);
void (*spin_lock)(struct raw_spinlock *lock);
+ void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags);
int (*spin_trylock)(struct raw_spinlock *lock);
void (*spin_unlock)(struct raw_spinlock *lock);
};
@@ -830,6 +834,16 @@ do { \
(aux) = __aux; \
} while (0)
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+ PVOP_VCALL2(pv_cpu_ops.alloc_ldt, ldt, entries);
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+ PVOP_VCALL2(pv_cpu_ops.free_ldt, ldt, entries);
+}
+
static inline void load_TR_desc(void)
{
PVOP_VCALL0(pv_cpu_ops.load_tr_desc);
@@ -1394,6 +1408,12 @@ static __always_inline void __raw_spin_lock(struct raw_spinlock *lock)
PVOP_VCALL1(pv_lock_ops.spin_lock, lock);
}
+static __always_inline void __raw_spin_lock_flags(struct raw_spinlock *lock,
+ unsigned long flags)
+{
+ PVOP_VCALL2(pv_lock_ops.spin_lock_flags, lock, flags);
+}
+
static __always_inline int __raw_spin_trylock(struct raw_spinlock *lock)
{
return PVOP_CALL1(int, pv_lock_ops.spin_trylock, lock);
diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h
index ed932453ef2..182f9d4c570 100644
--- a/include/asm-x86/pgtable.h
+++ b/include/asm-x86/pgtable.h
@@ -15,7 +15,7 @@
#define _PAGE_BIT_PAT 7 /* on 4KB pages */
#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */
#define _PAGE_BIT_UNUSED1 9 /* available for programmer */
-#define _PAGE_BIT_UNUSED2 10
+#define _PAGE_BIT_IOMAP 10 /* flag used to indicate IO mapping */
#define _PAGE_BIT_UNUSED3 11
#define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */
#define _PAGE_BIT_SPECIAL _PAGE_BIT_UNUSED1
@@ -32,7 +32,7 @@
#define _PAGE_PSE (_AT(pteval_t, 1) << _PAGE_BIT_PSE)
#define _PAGE_GLOBAL (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
#define _PAGE_UNUSED1 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1)
-#define _PAGE_UNUSED2 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED2)
+#define _PAGE_IOMAP (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP)
#define _PAGE_UNUSED3 (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3)
#define _PAGE_PAT (_AT(pteval_t, 1) << _PAGE_BIT_PAT)
#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
@@ -99,6 +99,11 @@
#define __PAGE_KERNEL_LARGE_NOCACHE (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE)
+#define __PAGE_KERNEL_IO (__PAGE_KERNEL | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_NOCACHE (__PAGE_KERNEL_NOCACHE | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_UC_MINUS (__PAGE_KERNEL_UC_MINUS | _PAGE_IOMAP)
+#define __PAGE_KERNEL_IO_WC (__PAGE_KERNEL_WC | _PAGE_IOMAP)
+
#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)
#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
@@ -113,6 +118,11 @@
#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL)
#define PAGE_KERNEL_VSYSCALL_NOCACHE __pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE)
+#define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO)
+#define PAGE_KERNEL_IO_NOCACHE __pgprot(__PAGE_KERNEL_IO_NOCACHE)
+#define PAGE_KERNEL_IO_UC_MINUS __pgprot(__PAGE_KERNEL_IO_UC_MINUS)
+#define PAGE_KERNEL_IO_WC __pgprot(__PAGE_KERNEL_IO_WC)
+
/* xwr */
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
@@ -196,7 +206,7 @@ static inline int pte_exec(pte_t pte)
static inline int pte_special(pte_t pte)
{
- return pte_val(pte) & _PAGE_SPECIAL;
+ return pte_flags(pte) & _PAGE_SPECIAL;
}
static inline unsigned long pte_pfn(pte_t pte)
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index c7d35464a4b..ee7cbb30773 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -586,41 +586,6 @@ static inline void clear_in_cr4(unsigned long mask)
write_cr4(cr4);
}
-struct microcode_header {
- unsigned int hdrver;
- unsigned int rev;
- unsigned int date;
- unsigned int sig;
- unsigned int cksum;
- unsigned int ldrver;
- unsigned int pf;
- unsigned int datasize;
- unsigned int totalsize;
- unsigned int reserved[3];
-};
-
-struct microcode {
- struct microcode_header hdr;
- unsigned int bits[0];
-};
-
-typedef struct microcode microcode_t;
-typedef struct microcode_header microcode_header_t;
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
- unsigned int sig;
- unsigned int pf;
- unsigned int cksum;
-};
-
-struct extended_sigtable {
- unsigned int count;
- unsigned int cksum;
- unsigned int reserved[3];
- struct extended_signature sigs[0];
-};
-
typedef struct {
unsigned long seg;
} mm_segment_t;
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index d64a6109716..a2025525a15 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -174,13 +174,9 @@ extern unsigned long profile_pc(struct pt_regs *regs);
extern unsigned long
convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
-
-#ifdef CONFIG_X86_32
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
- int error_code);
-#else
+ int error_code, int si_code);
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
-#endif
extern long syscall_trace_enter(struct pt_regs *);
extern void syscall_trace_leave(struct pt_regs *);
diff --git a/include/asm-x86/segment.h b/include/asm-x86/segment.h
index ea5f0a8686f..5d6e6945489 100644
--- a/include/asm-x86/segment.h
+++ b/include/asm-x86/segment.h
@@ -131,12 +131,6 @@
* Matching rules for certain types of segments.
*/
-/* Matches only __KERNEL_CS, ignoring PnP / USER / APM segments */
-#define SEGMENT_IS_KERNEL_CODE(x) (((x) & 0xfc) == GDT_ENTRY_KERNEL_CS * 8)
-
-/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */
-#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8)
-
/* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */
#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8)
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 29324c10334..a6afc29f2dd 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -50,12 +50,16 @@ extern struct {
struct smp_ops {
void (*smp_prepare_boot_cpu)(void);
void (*smp_prepare_cpus)(unsigned max_cpus);
- int (*cpu_up)(unsigned cpu);
void (*smp_cpus_done)(unsigned max_cpus);
void (*smp_send_stop)(void);
void (*smp_send_reschedule)(int cpu);
+ int (*cpu_up)(unsigned cpu);
+ int (*cpu_disable)(void);
+ void (*cpu_die)(unsigned int cpu);
+ void (*play_dead)(void);
+
void (*send_call_func_ipi)(cpumask_t mask);
void (*send_call_func_single_ipi)(int cpu);
};
@@ -94,6 +98,21 @@ static inline int __cpu_up(unsigned int cpu)
return smp_ops.cpu_up(cpu);
}
+static inline int __cpu_disable(void)
+{
+ return smp_ops.cpu_disable();
+}
+
+static inline void __cpu_die(unsigned int cpu)
+{
+ smp_ops.cpu_die(cpu);
+}
+
+static inline void play_dead(void)
+{
+ smp_ops.play_dead();
+}
+
static inline void smp_send_reschedule(int cpu)
{
smp_ops.smp_send_reschedule(cpu);
@@ -109,15 +128,20 @@ static inline void arch_send_call_function_ipi(cpumask_t mask)
smp_ops.send_call_func_ipi(mask);
}
+void cpu_disable_common(void);
void native_smp_prepare_boot_cpu(void);
void native_smp_prepare_cpus(unsigned int max_cpus);
void native_smp_cpus_done(unsigned int max_cpus);
int native_cpu_up(unsigned int cpunum);
+int native_cpu_disable(void);
+void native_cpu_die(unsigned int cpu);
+void native_play_dead(void);
+void play_dead_common(void);
+
void native_send_call_func_ipi(cpumask_t mask);
void native_send_call_func_single_ipi(int cpu);
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
+extern void prefill_possible_map(void);
void smp_store_cpu_info(int id);
#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu)
@@ -127,15 +151,11 @@ static inline int num_booting_cpus(void)
{
return cpus_weight(cpu_callout_map);
}
-#endif /* CONFIG_SMP */
-
-#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_CPU)
-extern void prefill_possible_map(void);
#else
static inline void prefill_possible_map(void)
{
}
-#endif
+#endif /* CONFIG_SMP */
extern unsigned disabled_cpus __cpuinitdata;
@@ -205,9 +225,5 @@ static inline int hard_smp_processor_id(void)
#endif /* CONFIG_X86_LOCAL_APIC */
-#ifdef CONFIG_HOTPLUG_CPU
-extern void cpu_uninit(void);
-#endif
-
#endif /* __ASSEMBLY__ */
#endif /* ASM_X86__SMP_H */
diff --git a/include/asm-x86/spinlock.h b/include/asm-x86/spinlock.h
index 93adae338ac..157ff7fab97 100644
--- a/include/asm-x86/spinlock.h
+++ b/include/asm-x86/spinlock.h
@@ -21,8 +21,10 @@
#ifdef CONFIG_X86_32
# define LOCK_PTR_REG "a"
+# define REG_PTR_MODE "k"
#else
# define LOCK_PTR_REG "D"
+# define REG_PTR_MODE "q"
#endif
#if defined(CONFIG_X86_32) && \
@@ -54,19 +56,7 @@
* much between them in performance though, especially as locks are out of line.
*/
#if (NR_CPUS < 256)
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 8) & 0xff) != (tmp & 0xff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 8) - tmp) & 0xff) > 1;
-}
+#define TICKET_SHIFT 8
static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
{
@@ -89,19 +79,17 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
{
- int tmp;
- short new;
+ int tmp, new;
- asm volatile("movw %2,%w0\n\t"
+ asm volatile("movzwl %2, %0\n\t"
"cmpb %h0,%b0\n\t"
+ "leal 0x100(%" REG_PTR_MODE "0), %1\n\t"
"jne 1f\n\t"
- "movw %w0,%w1\n\t"
- "incb %h1\n\t"
LOCK_PREFIX "cmpxchgw %w1,%2\n\t"
"1:"
"sete %b1\n\t"
"movzbl %b1,%0\n\t"
- : "=&a" (tmp), "=Q" (new), "+m" (lock->slock)
+ : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
:
: "memory", "cc");
@@ -116,19 +104,7 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
: "memory", "cc");
}
#else
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 16) & 0xffff) != (tmp & 0xffff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
- int tmp = ACCESS_ONCE(lock->slock);
-
- return (((tmp >> 16) - tmp) & 0xffff) > 1;
-}
+#define TICKET_SHIFT 16
static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
{
@@ -146,7 +122,7 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
/* don't need lfence here, because loads are in-order */
"jmp 1b\n"
"2:"
- : "+Q" (inc), "+m" (lock->slock), "=r" (tmp)
+ : "+r" (inc), "+m" (lock->slock), "=&r" (tmp)
:
: "memory", "cc");
}
@@ -160,13 +136,13 @@ static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
"movl %0,%1\n\t"
"roll $16, %0\n\t"
"cmpl %0,%1\n\t"
+ "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t"
"jne 1f\n\t"
- "addl $0x00010000, %1\n\t"
LOCK_PREFIX "cmpxchgl %1,%2\n\t"
"1:"
"sete %b1\n\t"
"movzbl %b1,%0\n\t"
- : "=&a" (tmp), "=r" (new), "+m" (lock->slock)
+ : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
:
: "memory", "cc");
@@ -182,7 +158,19 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
}
#endif
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
+{
+ int tmp = ACCESS_ONCE(lock->slock);
+
+ return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1));
+}
+
+static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
+{
+ int tmp = ACCESS_ONCE(lock->slock);
+
+ return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1;
+}
#ifdef CONFIG_PARAVIRT
/*
@@ -272,6 +260,13 @@ static __always_inline void __raw_spin_unlock(raw_spinlock_t *lock)
{
__ticket_spin_unlock(lock);
}
+
+static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,
+ unsigned long flags)
+{
+ __raw_spin_lock(lock);
+}
+
#endif /* CONFIG_PARAVIRT */
static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
diff --git a/include/asm-x86/statfs.h b/include/asm-x86/statfs.h
index 3f005bc3aa5..ca5dc19dd46 100644
--- a/include/asm-x86/statfs.h
+++ b/include/asm-x86/statfs.h
@@ -1,63 +1,12 @@
#ifndef ASM_X86__STATFS_H
#define ASM_X86__STATFS_H
-#ifdef __i386__
-#include <asm-generic/statfs.h>
-#else
-
-#ifndef __KERNEL_STRICT_NAMES
-
-#include <linux/types.h>
-
-typedef __kernel_fsid_t fsid_t;
-
-#endif
-
/*
- * This is ugly -- we're already 64-bit clean, so just duplicate the
- * definitions.
+ * We need compat_statfs64 to be packed, because the i386 ABI won't
+ * add padding at the end to bring it to a multiple of 8 bytes, but
+ * the x86_64 ABI will.
*/
-struct statfs {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
-
-struct statfs64 {
- long f_type;
- long f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
- __kernel_fsid_t f_fsid;
- long f_namelen;
- long f_frsize;
- long f_spare[5];
-};
+#define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4)))
-struct compat_statfs64 {
- __u32 f_type;
- __u32 f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_spare[5];
-} __attribute__((packed));
-
-#endif /* !__i386__ */
+#include <asm-generic/statfs.h>
#endif /* ASM_X86__STATFS_H */
diff --git a/include/asm-x86/system.h b/include/asm-x86/system.h
index 34505dd7b24..b20c894660f 100644
--- a/include/asm-x86/system.h
+++ b/include/asm-x86/system.h
@@ -64,7 +64,10 @@ do { \
\
/* regparm parameters for __switch_to(): */ \
[prev] "a" (prev), \
- [next] "d" (next)); \
+ [next] "d" (next) \
+ \
+ : /* reloaded segment registers */ \
+ "memory"); \
} while (0)
/*
diff --git a/include/asm-x86/tlbflush.h b/include/asm-x86/tlbflush.h
index ef68b76dc3c..3cdd08b5bdb 100644
--- a/include/asm-x86/tlbflush.h
+++ b/include/asm-x86/tlbflush.h
@@ -119,6 +119,10 @@ static inline void native_flush_tlb_others(const cpumask_t *cpumask,
{
}
+static inline void reset_lazy_tlbstate(void)
+{
+}
+
#else /* SMP */
#include <asm/smp.h>
@@ -151,6 +155,12 @@ struct tlb_state {
char __cacheline_padding[L1_CACHE_BYTES-8];
};
DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
+
+void reset_lazy_tlbstate(void);
+#else
+static inline void reset_lazy_tlbstate(void)
+{
+}
#endif
#endif /* SMP */
diff --git a/include/asm-x86/traps.h b/include/asm-x86/traps.h
index 2ccebc6fb0b..6c3dc2c6575 100644
--- a/include/asm-x86/traps.h
+++ b/include/asm-x86/traps.h
@@ -1,7 +1,14 @@
#ifndef ASM_X86__TRAPS_H
#define ASM_X86__TRAPS_H
-/* Common in X86_32 and X86_64 */
+#include <asm/debugreg.h>
+
+#ifdef CONFIG_X86_32
+#define dotraplinkage
+#else
+#define dotraplinkage asmlinkage
+#endif
+
asmlinkage void divide_error(void);
asmlinkage void debug(void);
asmlinkage void nmi(void);
@@ -10,61 +17,65 @@ asmlinkage void overflow(void);
asmlinkage void bounds(void);
asmlinkage void invalid_op(void);
asmlinkage void device_not_available(void);
+#ifdef CONFIG_X86_64
+asmlinkage void double_fault(void);
+#endif
asmlinkage void coprocessor_segment_overrun(void);
asmlinkage void invalid_TSS(void);
asmlinkage void segment_not_present(void);
asmlinkage void stack_segment(void);
asmlinkage void general_protection(void);
asmlinkage void page_fault(void);
+asmlinkage void spurious_interrupt_bug(void);
asmlinkage void coprocessor_error(void);
-asmlinkage void simd_coprocessor_error(void);
asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
#ifdef CONFIG_X86_MCE
asmlinkage void machine_check(void);
#endif /* CONFIG_X86_MCE */
+asmlinkage void simd_coprocessor_error(void);
+
+dotraplinkage void do_divide_error(struct pt_regs *, long);
+dotraplinkage void do_debug(struct pt_regs *, long);
+dotraplinkage void do_nmi(struct pt_regs *, long);
+dotraplinkage void do_int3(struct pt_regs *, long);
+dotraplinkage void do_overflow(struct pt_regs *, long);
+dotraplinkage void do_bounds(struct pt_regs *, long);
+dotraplinkage void do_invalid_op(struct pt_regs *, long);
+dotraplinkage void do_device_not_available(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *, long);
+dotraplinkage void do_invalid_TSS(struct pt_regs *, long);
+dotraplinkage void do_segment_not_present(struct pt_regs *, long);
+dotraplinkage void do_stack_segment(struct pt_regs *, long);
+dotraplinkage void do_general_protection(struct pt_regs *, long);
+dotraplinkage void do_page_fault(struct pt_regs *, unsigned long);
+dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long);
+dotraplinkage void do_coprocessor_error(struct pt_regs *, long);
+dotraplinkage void do_alignment_check(struct pt_regs *, long);
+#ifdef CONFIG_X86_MCE
+dotraplinkage void do_machine_check(struct pt_regs *, long);
+#endif
+dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
+#ifdef CONFIG_X86_32
+dotraplinkage void do_iret_error(struct pt_regs *, long);
+#endif
-void do_divide_error(struct pt_regs *, long);
-void do_overflow(struct pt_regs *, long);
-void do_bounds(struct pt_regs *, long);
-void do_coprocessor_segment_overrun(struct pt_regs *, long);
-void do_invalid_TSS(struct pt_regs *, long);
-void do_segment_not_present(struct pt_regs *, long);
-void do_stack_segment(struct pt_regs *, long);
-void do_alignment_check(struct pt_regs *, long);
-void do_invalid_op(struct pt_regs *, long);
-void do_general_protection(struct pt_regs *, long);
-void do_nmi(struct pt_regs *, long);
+static inline int get_si_code(unsigned long condition)
+{
+ if (condition & DR_STEP)
+ return TRAP_TRACE;
+ else if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))
+ return TRAP_HWBKPT;
+ else
+ return TRAP_BRKPT;
+}
extern int panic_on_unrecovered_nmi;
extern int kstack_depth_to_print;
#ifdef CONFIG_X86_32
-
-void do_iret_error(struct pt_regs *, long);
-void do_int3(struct pt_regs *, long);
-void do_debug(struct pt_regs *, long);
void math_error(void __user *);
-void do_coprocessor_error(struct pt_regs *, long);
-void do_simd_coprocessor_error(struct pt_regs *, long);
-void do_spurious_interrupt_bug(struct pt_regs *, long);
unsigned long patch_espfix_desc(unsigned long, unsigned long);
asmlinkage void math_emulate(long);
+#endif
-void do_page_fault(struct pt_regs *regs, unsigned long error_code);
-
-#else /* CONFIG_X86_32 */
-
-asmlinkage void double_fault(void);
-
-asmlinkage void do_int3(struct pt_regs *, long);
-asmlinkage void do_stack_segment(struct pt_regs *, long);
-asmlinkage void do_debug(struct pt_regs *, unsigned long);
-asmlinkage void do_coprocessor_error(struct pt_regs *);
-asmlinkage void do_simd_coprocessor_error(struct pt_regs *);
-asmlinkage void do_spurious_interrupt_bug(struct pt_regs *);
-
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code);
-
-#endif /* CONFIG_X86_32 */
#endif /* ASM_X86__TRAPS_H */
diff --git a/include/asm-x86/xen/hypervisor.h b/include/asm-x86/xen/hypervisor.h
index 0ef3a88b869..445a2475956 100644
--- a/include/asm-x86/xen/hypervisor.h
+++ b/include/asm-x86/xen/hypervisor.h
@@ -54,7 +54,6 @@
/* arch/i386/kernel/setup.c */
extern struct shared_info *HYPERVISOR_shared_info;
extern struct start_info *xen_start_info;
-#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
/* arch/i386/mach-xen/evtchn.c */
/* Force a proper event-channel callback from Xen. */
@@ -67,6 +66,17 @@ u64 jiffies_to_st(unsigned long jiffies);
#define MULTI_UVMFLAGS_INDEX 3
#define MULTI_UVMDOMID_INDEX 4
-#define is_running_on_xen() (xen_start_info ? 1 : 0)
+enum xen_domain_type {
+ XEN_NATIVE,
+ XEN_PV_DOMAIN,
+ XEN_HVM_DOMAIN,
+};
+
+extern enum xen_domain_type xen_domain_type;
+
+#define xen_domain() (xen_domain_type != XEN_NATIVE)
+#define xen_pv_domain() (xen_domain_type == XEN_PV_DOMAIN)
+#define xen_initial_domain() (xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN)
+#define xen_hvm_domain() (xen_domain_type == XEN_HVM_DOMAIN)
#endif /* ASM_X86__XEN__HYPERVISOR_H */
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
deleted file mode 100644
index fdf13702924..00000000000
--- a/include/asm-xtensa/a.out.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * include/asm-xtensa/a.out.h
- *
- * Dummy a.out file. Xtensa does not support the a.out format, but the kernel
- * seems to depend on it.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_A_OUT_H
-#define _XTENSA_A_OUT_H
-
-struct exec
-{
- unsigned long a_info;
- unsigned a_text;
- unsigned a_data;
- unsigned a_bss;
- unsigned a_syms;
- unsigned a_entry;
- unsigned a_trsize;
- unsigned a_drsize;
-};
-
-#endif /* _XTENSA_A_OUT_H */
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index 154769cad3f..5ce0e5fd712 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -17,20 +17,31 @@
#ifdef CONFIG_UNIX98_PTYS
-int devpts_new_index(void);
-void devpts_kill_index(int idx);
-int devpts_pty_new(struct tty_struct *tty); /* mknod in devpts */
-struct tty_struct *devpts_get_tty(int number); /* get tty structure */
-void devpts_pty_kill(int number); /* unlink */
+int devpts_new_index(struct inode *ptmx_inode);
+void devpts_kill_index(struct inode *ptmx_inode, int idx);
+/* mknod in devpts */
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty);
+/* get tty structure */
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number);
+/* unlink */
+void devpts_pty_kill(struct tty_struct *tty);
#else
/* Dummy stubs in the no-pty case */
-static inline int devpts_new_index(void) { return -EINVAL; }
-static inline void devpts_kill_index(int idx) { }
-static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; }
-static inline struct tty_struct *devpts_get_tty(int number) { return NULL; }
-static inline void devpts_pty_kill(int number) { }
+static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
+static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
+static inline int devpts_pty_new(struct inode *ptmx_inode,
+ struct tty_struct *tty)
+{
+ return -EINVAL;
+}
+static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode,
+ int number)
+{
+ return NULL;
+}
+static inline void devpts_pty_kill(struct tty_struct *tty) { }
#endif
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 2a063b64133..e5084eb5943 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -2,29 +2,9 @@
#define __DMI_H__
#include <linux/list.h>
+#include <linux/mod_devicetable.h>
-enum dmi_field {
- DMI_NONE,
- DMI_BIOS_VENDOR,
- DMI_BIOS_VERSION,
- DMI_BIOS_DATE,
- DMI_SYS_VENDOR,
- DMI_PRODUCT_NAME,
- DMI_PRODUCT_VERSION,
- DMI_PRODUCT_SERIAL,
- DMI_PRODUCT_UUID,
- DMI_BOARD_VENDOR,
- DMI_BOARD_NAME,
- DMI_BOARD_VERSION,
- DMI_BOARD_SERIAL,
- DMI_BOARD_ASSET_TAG,
- DMI_CHASSIS_VENDOR,
- DMI_CHASSIS_TYPE,
- DMI_CHASSIS_VERSION,
- DMI_CHASSIS_SERIAL,
- DMI_CHASSIS_ASSET_TAG,
- DMI_STRING_MAX,
-};
+/* enum dmi_field is in mod_devicetable.h */
enum dmi_device_type {
DMI_DEV_TYPE_ANY = 0,
@@ -48,23 +28,6 @@ struct dmi_header {
u16 handle;
};
-/*
- * DMI callbacks for problem boards
- */
-struct dmi_strmatch {
- u8 slot;
- char *substr;
-};
-
-struct dmi_system_id {
- int (*callback)(const struct dmi_system_id *);
- const char *ident;
- struct dmi_strmatch matches[4];
- void *driver_data;
-};
-
-#define DMI_MATCH(a, b) { a, b }
-
struct dmi_device {
struct list_head list;
int type;
diff --git a/include/linux/elf.h b/include/linux/elf.h
index edc3dac3f02..0b61ca41a04 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -360,6 +360,7 @@ typedef struct elf64_shdr {
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
/* Note header in a PT_NOTE section */
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 2dc29ce6c8e..79f63a27bce 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -37,6 +37,7 @@ struct hpet {
#define hpet_compare _u1._hpet_compare
#define HPET_MAX_TIMERS (32)
+#define HPET_MAX_IRQ (32)
/*
* HPET general capabilities register
@@ -64,7 +65,7 @@ struct hpet {
*/
#define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL)
-#define Tn_INI_ROUTE_CAP_SHIFT (32UL)
+#define Tn_INT_ROUTE_CAP_SHIFT (32UL)
#define Tn_FSB_INT_DELCAP_MASK (0x8000UL)
#define Tn_FSB_INT_DELCAP_SHIFT (15)
#define Tn_FSB_EN_CNF_MASK (0x4000UL)
@@ -91,23 +92,14 @@ struct hpet {
* exported interfaces
*/
-struct hpet_task {
- void (*ht_func) (void *);
- void *ht_data;
- void *ht_opaque;
-};
-
struct hpet_data {
unsigned long hd_phys_address;
void __iomem *hd_address;
unsigned short hd_nirqs;
- unsigned short hd_flags;
unsigned int hd_state; /* timer allocated */
unsigned int hd_irq[HPET_MAX_TIMERS];
};
-#define HPET_DATA_PLATFORM 0x0001 /* platform call to hpet_alloc */
-
static inline void hpet_reserve_timer(struct hpet_data *hd, int timer)
{
hd->hd_state |= (1 << timer);
@@ -125,7 +117,7 @@ struct hpet_info {
unsigned short hi_timer;
};
-#define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */
+#define HPET_INFO_PERIODIC 0x0010 /* periodic-capable comparator */
#define HPET_IE_ON _IO('h', 0x01) /* interrupt on */
#define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 66c3499478b..d2e91ea998f 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -967,6 +967,9 @@ struct journal_s
#define JBD2_FLUSHED 0x008 /* The journal superblock has been flushed */
#define JBD2_LOADED 0x010 /* The journal superblock has been loaded */
#define JBD2_BARRIER 0x020 /* Use IDE barriers */
+#define JBD2_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file
+ * data write error in ordered
+ * mode */
/*
* Function declarations for the journaling transaction and buffer
@@ -1060,7 +1063,7 @@ extern void jbd2_journal_clear_features
(journal_t *, unsigned long, unsigned long, unsigned long);
extern int jbd2_journal_create (journal_t *);
extern int jbd2_journal_load (journal_t *journal);
-extern void jbd2_journal_destroy (journal_t *);
+extern int jbd2_journal_destroy (journal_t *);
extern int jbd2_journal_recover (journal_t *journal);
extern int jbd2_journal_wipe (journal_t *, int);
extern int jbd2_journal_skip_recovery (journal_t *);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 2651f805ba6..75d81f157d2 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -182,7 +182,7 @@ extern int vsscanf(const char *, const char *, va_list)
extern int get_option(char **str, int *pint);
extern char *get_options(const char *str, int nints, int *ints);
-extern unsigned long long memparse(char *ptr, char **retptr);
+extern unsigned long long memparse(const char *ptr, char **retptr);
extern int core_kernel_text(unsigned long addr);
extern int __kernel_text_address(unsigned long addr);
diff --git a/include/linux/key.h b/include/linux/key.h
index c45c962d1cc..1b70e35a71e 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -299,6 +299,7 @@ extern void key_init(void);
#define key_validate(k) 0
#define key_serial(k) 0
#define key_get(k) ({ NULL; })
+#define key_revoke(k) do { } while(0)
#define key_put(k) do { } while(0)
#define key_ref_put(k) do { } while(0)
#define make_key_ref(k, p) ({ NULL; })
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 1fa0c2ce4de..f7f3fdddbef 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -6,6 +6,10 @@
#define AFS_SUPER_MAGIC 0x5346414F
#define AUTOFS_SUPER_MAGIC 0x0187
#define CODA_SUPER_MAGIC 0x73757245
+#define DEBUGFS_MAGIC 0x64626720
+#define SYSFS_MAGIC 0x62656572
+#define SECURITYFS_MAGIC 0x73636673
+#define TMPFS_MAGIC 0x01021994
#define EFS_SUPER_MAGIC 0x414A53
#define EXT2_SUPER_MAGIC 0xEF53
#define EXT3_SUPER_MAGIC 0xEF53
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 72a15dc26bb..c61ba10768e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -7,6 +7,7 @@
#include <linux/gfp.h>
#include <linux/list.h>
+#include <linux/mmdebug.h>
#include <linux/mmzone.h>
#include <linux/rbtree.h>
#include <linux/prio_tree.h>
@@ -219,12 +220,6 @@ struct inode;
*/
#include <linux/page-flags.h>
-#ifdef CONFIG_DEBUG_VM
-#define VM_BUG_ON(cond) BUG_ON(cond)
-#else
-#define VM_BUG_ON(condition) do { } while(0)
-#endif
-
/*
* Methods to modify the page usage count.
*
@@ -919,7 +914,7 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
}
#endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
/*
* We tuck a spinlock to guard each pagetable page into its struct page,
* at page->private, with BUILD_BUG_ON to make sure that this will not
@@ -932,14 +927,14 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
} while (0)
#define pte_lock_deinit(page) ((page)->mapping = NULL)
#define pte_lockptr(mm, pmd) ({(void)(mm); __pte_lockptr(pmd_page(*(pmd)));})
-#else
+#else /* !USE_SPLIT_PTLOCKS */
/*
* We use mm->page_table_lock to guard all pagetable pages of the mm.
*/
#define pte_lock_init(page) do {} while (0)
#define pte_lock_deinit(page) do {} while (0)
#define pte_lockptr(mm, pmd) ({(void)(pmd); &(mm)->page_table_lock;})
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* USE_SPLIT_PTLOCKS */
static inline void pgtable_page_ctor(struct page *page)
{
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index bf334138c7c..9d49fa36bbe 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -21,11 +21,13 @@
struct address_space;
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#define USE_SPLIT_PTLOCKS (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS)
+
+#if USE_SPLIT_PTLOCKS
typedef atomic_long_t mm_counter_t;
-#else /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else /* !USE_SPLIT_PTLOCKS */
typedef unsigned long mm_counter_t;
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
/*
* Each physical page in the system has a struct page associated with
@@ -65,7 +67,7 @@ struct page {
* see PAGE_MAPPING_ANON below.
*/
};
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
spinlock_t ptl;
#endif
struct kmem_cache *slab; /* SLUB: Pointer to slab */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9c288c90987..bde891f6459 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -65,7 +65,7 @@ struct mmc_host_ops {
* -ENOSYS when not supported (equal to NULL callback)
* or a negative errno value when something bad happened
*
- * Return values for the get_ro callback should be:
+ * Return values for the get_cd callback should be:
* 0 for a absent card
* 1 for a present card
* -ENOSYS when not supported (equal to NULL callback)
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
new file mode 100644
index 00000000000..8a550987719
--- /dev/null
+++ b/include/linux/mmdebug.h
@@ -0,0 +1,18 @@
+#ifndef LINUX_MM_DEBUG_H
+#define LINUX_MM_DEBUG_H 1
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_DEBUG_VM
+#define VM_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VM_BUG_ON(cond) do { } while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+#define VIRTUAL_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VIRTUAL_BUG_ON(cond) do { } while (0)
+#endif
+
+#endif
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index c4db5827963..3481a7d5bc0 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -388,5 +388,52 @@ struct i2c_device_id {
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
+/* dmi */
+enum dmi_field {
+ DMI_NONE,
+ DMI_BIOS_VENDOR,
+ DMI_BIOS_VERSION,
+ DMI_BIOS_DATE,
+ DMI_SYS_VENDOR,
+ DMI_PRODUCT_NAME,
+ DMI_PRODUCT_VERSION,
+ DMI_PRODUCT_SERIAL,
+ DMI_PRODUCT_UUID,
+ DMI_BOARD_VENDOR,
+ DMI_BOARD_NAME,
+ DMI_BOARD_VERSION,
+ DMI_BOARD_SERIAL,
+ DMI_BOARD_ASSET_TAG,
+ DMI_CHASSIS_VENDOR,
+ DMI_CHASSIS_TYPE,
+ DMI_CHASSIS_VERSION,
+ DMI_CHASSIS_SERIAL,
+ DMI_CHASSIS_ASSET_TAG,
+ DMI_STRING_MAX,
+};
+
+struct dmi_strmatch {
+ unsigned char slot;
+ char substr[79];
+};
+
+#ifndef __KERNEL__
+struct dmi_system_id {
+ kernel_ulong_t callback;
+ kernel_ulong_t ident;
+ struct dmi_strmatch matches[4];
+ kernel_ulong_t driver_data
+ __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+#else
+struct dmi_system_id {
+ int (*callback)(const struct dmi_system_id *);
+ const char *ident;
+ struct dmi_strmatch matches[4];
+ void *driver_data;
+};
+#endif
+
+#define DMI_MATCH(a, b) { a, b }
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 041bb31100f..bcb8f725427 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -36,6 +36,8 @@
#define XEN_ENTER_SWITCH_CODE 10
#define SPU_PROFILING_CODE 11
#define SPU_CTX_SWITCH_CODE 12
+#define IBS_FETCH_CODE 13
+#define IBS_OP_CODE 14
struct super_block;
struct dentry;
diff --git a/include/linux/parser.h b/include/linux/parser.h
index 7dcd0507575..ea2281e726f 100644
--- a/include/linux/parser.h
+++ b/include/linux/parser.h
@@ -25,7 +25,7 @@ typedef struct {
char *to;
} substring_t;
-int match_token(char *, match_table_t table, substring_t args[]);
+int match_token(char *, const match_table_t table, substring_t args[]);
int match_int(substring_t *, int *result);
int match_octal(substring_t *, int *result);
int match_hex(substring_t *, int *result);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index f63b5455801..1176f1f177e 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1533,7 +1533,9 @@
#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480
-#define PCI_DEVICE_ID_MARVELL_CAFE_SD 0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND 0x4100
+#define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102
#define PCI_VENDOR_ID_V3 0x11b0
#define PCI_DEVICE_ID_V3_V960 0x0001
diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h
index e8c7c21ceb1..6fc961459b4 100644
--- a/include/linux/rtc/m48t59.h
+++ b/include/linux/rtc/m48t59.h
@@ -18,40 +18,47 @@
/*
* M48T59 Register Offset
*/
-#define M48T59_YEAR 0x1fff
-#define M48T59_MONTH 0x1ffe
-#define M48T59_MDAY 0x1ffd /* Day of Month */
-#define M48T59_WDAY 0x1ffc /* Day of Week */
+#define M48T59_YEAR 0xf
+#define M48T59_MONTH 0xe
+#define M48T59_MDAY 0xd /* Day of Month */
+#define M48T59_WDAY 0xc /* Day of Week */
#define M48T59_WDAY_CB 0x20 /* Century Bit */
#define M48T59_WDAY_CEB 0x10 /* Century Enable Bit */
-#define M48T59_HOUR 0x1ffb
-#define M48T59_MIN 0x1ffa
-#define M48T59_SEC 0x1ff9
-#define M48T59_CNTL 0x1ff8
+#define M48T59_HOUR 0xb
+#define M48T59_MIN 0xa
+#define M48T59_SEC 0x9
+#define M48T59_CNTL 0x8
#define M48T59_CNTL_READ 0x40
#define M48T59_CNTL_WRITE 0x80
-#define M48T59_WATCHDOG 0x1ff7
-#define M48T59_INTR 0x1ff6
+#define M48T59_WATCHDOG 0x7
+#define M48T59_INTR 0x6
#define M48T59_INTR_AFE 0x80 /* Alarm Interrupt Enable */
#define M48T59_INTR_ABE 0x20
-#define M48T59_ALARM_DATE 0x1ff5
-#define M48T59_ALARM_HOUR 0x1ff4
-#define M48T59_ALARM_MIN 0x1ff3
-#define M48T59_ALARM_SEC 0x1ff2
-#define M48T59_UNUSED 0x1ff1
-#define M48T59_FLAGS 0x1ff0
+#define M48T59_ALARM_DATE 0x5
+#define M48T59_ALARM_HOUR 0x4
+#define M48T59_ALARM_MIN 0x3
+#define M48T59_ALARM_SEC 0x2
+#define M48T59_UNUSED 0x1
+#define M48T59_FLAGS 0x0
#define M48T59_FLAGS_WDT 0x80 /* watchdog timer expired */
#define M48T59_FLAGS_AF 0x40 /* alarm */
#define M48T59_FLAGS_BF 0x10 /* low battery */
-#define M48T59_NVRAM_SIZE 0x1ff0
+#define M48T59RTC_TYPE_M48T59 0 /* to keep compatibility */
+#define M48T59RTC_TYPE_M48T02 1
+#define M48T59RTC_TYPE_M48T08 2
struct m48t59_plat_data {
- /* The method to access M48T59 registers,
- * NOTE: The 'ofs' should be 0x00~0x1fff
- */
+ /* The method to access M48T59 registers */
void (*write_byte)(struct device *dev, u32 ofs, u8 val);
unsigned char (*read_byte)(struct device *dev, u32 ofs);
+
+ int type; /* RTC model */
+
+ /* ioaddr mapped externally */
+ void __iomem *ioaddr;
+ /* offset to RTC registers, automatically set according to the type */
+ unsigned int offset;
};
#endif /* _LINUX_RTC_M48T59_H_ */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 5d0819ee442..c226c7b8294 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -352,7 +352,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
extern void arch_unmap_area(struct mm_struct *, unsigned long);
extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
/*
* The mm counters are not protected by its page_table_lock,
* so must be incremented atomically.
@@ -363,7 +363,7 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
#define inc_mm_counter(mm, member) atomic_long_inc(&(mm)->_##member)
#define dec_mm_counter(mm, member) atomic_long_dec(&(mm)->_##member)
-#else /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else /* !USE_SPLIT_PTLOCKS */
/*
* The mm counters are protected by its page_table_lock,
* so can be incremented directly.
@@ -374,7 +374,7 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
#define inc_mm_counter(mm, member) (mm)->_##member++
#define dec_mm_counter(mm, member) (mm)->_##member--
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
#define get_mm_rss(mm) \
(get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss))
diff --git a/include/linux/serial.h b/include/linux/serial.h
index deb714314fb..1ea8d9265bf 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -173,6 +173,22 @@ struct serial_icounter_struct {
int reserved[9];
};
+/*
+ * Serial interface for controlling RS485 settings on chips with suitable
+ * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
+ * platform. The set function returns the new state, with any unsupported bits
+ * reverted appropriately.
+ */
+
+struct serial_rs485 {
+ __u32 flags; /* RS485 feature flags */
+#define SER_RS485_ENABLED (1 << 0)
+#define SER_RS485_RTS_ON_SEND (1 << 1)
+#define SER_RS485_RTS_AFTER_SEND (1 << 2)
+ __u32 delay_rts_before_send; /* Milliseconds */
+ __u32 padding[6]; /* Memory is cheap, new structs
+ are a royal PITA .. */
+};
#ifdef __KERNEL__
#include <linux/compiler.h>
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 3b2f6c04855..e27f216361f 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t;
struct uart_port {
spinlock_t lock; /* port lock */
- unsigned int iobase; /* in/out[bwl] */
+ unsigned long iobase; /* in/out[bwl] */
unsigned char __iomem *membase; /* read/write[bwl] */
unsigned int irq; /* irq number */
unsigned int uartclk; /* base uart clock */
diff --git a/include/linux/termios.h b/include/linux/termios.h
index 478662889f4..2acd0c1f8a2 100644
--- a/include/linux/termios.h
+++ b/include/linux/termios.h
@@ -4,4 +4,19 @@
#include <linux/types.h>
#include <asm/termios.h>
+#define NFF 5
+
+struct termiox
+{
+ __u16 x_hflag;
+ __u16 x_cflag;
+ __u16 x_rflag[NFF];
+ __u16 x_sflag;
+};
+
+#define RTSXOFF 0x0001 /* RTS flow control on input */
+#define CTSXON 0x0002 /* CTS flow control on output */
+#define DTRXOFF 0x0004 /* DTR flow control on input */
+#define DSRXON 0x0008 /* DCD flow control on output */
+
#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 0cbec74ec08..3b8121d4e36 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -23,7 +23,7 @@
*/
#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS 18
+#define NR_LDISCS 19
/* line disciplines */
#define N_TTY 0
@@ -45,6 +45,7 @@
#define N_HCI 15 /* Bluetooth HCI UART */
#define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */
#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
+#define N_PPS 18 /* Pulse per Second */
/*
* This character is the same as _POSIX_VDISABLE: it cannot be used as
@@ -181,6 +182,7 @@ struct signal_struct;
struct tty_port {
struct tty_struct *tty; /* Back pointer */
+ spinlock_t lock; /* Lock protecting tty field */
int blocked_open; /* Waiting to open */
int count; /* Usage count */
wait_queue_head_t open_wait; /* Open waiters */
@@ -208,6 +210,7 @@ struct tty_operations;
struct tty_struct {
int magic;
+ struct kref kref;
struct tty_driver *driver;
const struct tty_operations *ops;
int index;
@@ -217,6 +220,7 @@ struct tty_struct {
spinlock_t ctrl_lock;
/* Termios values are protected by the termios mutex */
struct ktermios *termios, *termios_locked;
+ struct termiox *termiox; /* May be NULL for unsupported */
char name[64];
struct pid *pgrp; /* Protected by ctrl lock */
struct pid *session;
@@ -310,6 +314,25 @@ extern int kmsg_redirect;
extern void console_init(void);
extern int vcs_init(void);
+extern struct class *tty_class;
+
+/**
+ * tty_kref_get - get a tty reference
+ * @tty: tty device
+ *
+ * Return a new reference to a tty object. The caller must hold
+ * sufficient locks/counts to ensure that their existing reference cannot
+ * go away
+ */
+
+extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
+{
+ if (tty)
+ kref_get(&tty->kref);
+ return tty;
+}
+extern void tty_kref_put(struct tty_struct *tty);
+
extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
const char *routine);
extern char *tty_name(struct tty_struct *tty, char *buf);
@@ -333,13 +356,15 @@ extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(struct tty_struct *tty);
extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize *ws);
-
+extern void tty_shutdown(struct tty_struct *tty);
+extern void tty_free_termios(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void);
extern struct pid *tty_get_pgrp(struct tty_struct *tty);
extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty);
extern void tty_hangup(struct tty_struct *tty);
extern void tty_vhangup(struct tty_struct *tty);
+extern void tty_vhangup_self(void);
extern void tty_unhangup(struct file *filp);
extern int tty_hung_up_p(struct file *filp);
extern void do_SAK(struct tty_struct *tty);
@@ -347,6 +372,9 @@ extern void __do_SAK(struct tty_struct *tty);
extern void disassociate_ctty(int priv);
extern void no_tty(void);
extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern void tty_buffer_free_all(struct tty_struct *tty);
+extern void tty_buffer_flush(struct tty_struct *tty);
+extern void tty_buffer_init(struct tty_struct *tty);
extern speed_t tty_get_baud_rate(struct tty_struct *tty);
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
@@ -372,6 +400,15 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
extern dev_t tty_devnum(struct tty_struct *tty);
extern void proc_clear_tty(struct task_struct *p);
extern struct tty_struct *get_current_tty(void);
+extern void tty_default_fops(struct file_operations *fops);
+extern struct tty_struct *alloc_tty_struct(void);
+extern void free_tty_struct(struct tty_struct *tty);
+extern void initialize_tty_struct(struct tty_struct *tty,
+ struct tty_driver *driver, int idx);
+extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+ int first_ok);
+extern void tty_release_dev(struct file *filp);
+extern int tty_init_termios(struct tty_struct *tty);
extern struct mutex tty_mutex;
@@ -382,6 +419,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
extern void tty_port_init(struct tty_port *port);
extern int tty_port_alloc_xmit_buf(struct tty_port *port);
extern void tty_port_free_xmit_buf(struct tty_port *port);
+extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
+extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
extern int tty_unregister_ldisc(int disc);
@@ -427,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk,
#endif
/* tty_ioctl.c */
-extern int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
/* serial.c */
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 16d27944c32..78416b90158 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -7,6 +7,28 @@
* defined; unless noted otherwise, they are optional, and can be
* filled in with a null pointer.
*
+ * struct tty_struct * (*lookup)(struct tty_driver *self, int idx)
+ *
+ * Return the tty device corresponding to idx, NULL if there is not
+ * one currently in use and an ERR_PTR value on error. Called under
+ * tty_mutex (for now!)
+ *
+ * Optional method. Default behaviour is to use the ttys array
+ *
+ * int (*install)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ * Install a new tty into the tty driver internal tables. Used in
+ * conjunction with lookup and remove methods.
+ *
+ * Optional method. Default behaviour is to use the ttys array
+ *
+ * void (*remove)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ * Remove a closed tty from the tty driver internal tables. Used in
+ * conjunction with lookup and remove methods.
+ *
+ * Optional method. Default behaviour is to use the ttys array
+ *
* int (*open)(struct tty_struct * tty, struct file * filp);
*
* This routine is called when a particular tty device is opened.
@@ -21,6 +43,11 @@
*
* Required method.
*
+ * void (*shutdown)(struct tty_struct * tty);
+ *
+ * This routine is called when a particular tty device is closed for
+ * the last time freeing up the resources.
+ *
* int (*write)(struct tty_struct * tty,
* const unsigned char *buf, int count);
*
@@ -180,6 +207,14 @@
* not force errors here if they are not resizable objects (eg a serial
* line). See tty_do_resize() if you need to wrap the standard method
* in your own logic - the usual case.
+ *
+ * void (*set_termiox)(struct tty_struct *tty, struct termiox *new);
+ *
+ * Called when the device receives a termiox based ioctl. Passes down
+ * the requested data from user space. This method will not be invoked
+ * unless the tty also has a valid tty->termiox pointer.
+ *
+ * Optional: Called under the termios lock
*/
#include <linux/fs.h>
@@ -190,8 +225,13 @@ struct tty_struct;
struct tty_driver;
struct tty_operations {
+ struct tty_struct * (*lookup)(struct tty_driver *driver,
+ struct inode *inode, int idx);
+ int (*install)(struct tty_driver *driver, struct tty_struct *tty);
+ void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
+ void (*shutdown)(struct tty_struct *tty);
int (*write)(struct tty_struct * tty,
const unsigned char *buf, int count);
int (*put_char)(struct tty_struct *tty, unsigned char ch);
@@ -220,6 +260,7 @@ struct tty_operations {
unsigned int set, unsigned int clear);
int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize *ws);
+ int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line);
@@ -229,6 +270,7 @@ struct tty_operations {
struct tty_driver {
int magic; /* magic number for this structure */
+ struct kref kref; /* Reference management */
struct cdev cdev;
struct module *owner;
const char *driver_name;
@@ -242,7 +284,6 @@ struct tty_driver {
short subtype; /* subtype of tty driver */
struct ktermios init_termios; /* Initial termios */
int flags; /* tty driver flags */
- int refcount; /* for loadable tty drivers */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
struct tty_driver *other; /* only used for the PTY driver */
@@ -264,12 +305,19 @@ struct tty_driver {
extern struct list_head tty_drivers;
-struct tty_driver *alloc_tty_driver(int lines);
-void put_tty_driver(struct tty_driver *driver);
-void tty_set_operations(struct tty_driver *driver,
+extern struct tty_driver *alloc_tty_driver(int lines);
+extern void put_tty_driver(struct tty_driver *driver);
+extern void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op);
extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
+extern void tty_driver_kref_put(struct tty_driver *driver);
+extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
+{
+ kref_get(&d->kref);
+ return d;
+}
+
/* tty driver magic number */
#define TTY_DRIVER_MAGIC 0x5402
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
new file mode 100644
index 00000000000..5b88e36c910
--- /dev/null
+++ b/include/linux/usb/ehci_def.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_USB_EHCI_DEF_H
+#define __LINUX_USB_EHCI_DEF_H
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+ /* these fields are specified as 8 and 16 bit registers,
+ * but some hosts can't perform 8 or 16 bit PCI accesses.
+ */
+ u32 hc_capbase;
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
+ u32 hcs_params; /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
+#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+
+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
+#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
+ u8 portroute [8]; /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+ /* USBCMD: offset 0x00 */
+ u32 command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK (1<<11) /* enable "park" on async qh */
+#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
+#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
+#define CMD_ASE (1<<5) /* async schedule enable */
+#define CMD_PSE (1<<4) /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+
+ /* USBSTS: offset 0x04 */
+ u32 status;
+#define STS_ASS (1<<15) /* Async Schedule Status */
+#define STS_PSS (1<<14) /* Periodic Schedule Status */
+#define STS_RECL (1<<13) /* Reclamation */
+#define STS_HALT (1<<12) /* Not running (any reason) */
+/* some bits reserved */
+ /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA (1<<5) /* Interrupted on async advance */
+#define STS_FATAL (1<<4) /* such as some PCI access errors */
+#define STS_FLR (1<<3) /* frame list rolled over */
+#define STS_PCD (1<<2) /* port change detect */
+#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
+#define STS_INT (1<<0) /* "normal" completion (short, ...) */
+
+ /* USBINTR: offset 0x08 */
+ u32 intr_enable;
+
+ /* FRINDEX: offset 0x0C */
+ u32 frame_index; /* current microframe number */
+ /* CTRLDSSEGMENT: offset 0x10 */
+ u32 segment; /* address bits 63:32 if needed */
+ /* PERIODICLISTBASE: offset 0x14 */
+ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+
+ u32 reserved [9];
+
+ /* CONFIGFLAG: offset 0x40 */
+ u32 configured_flag;
+#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
+ /* PORTSC: offset 0x44 */
+ u32 port_status [0]; /* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
+#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK (3<<14)
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_OCC (1<<5) /* over current change */
+#define PORT_OC (1<<4) /* over current active */
+#define PORT_PEC (1<<3) /* port enable change */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
+} __attribute__ ((packed));
+
+#define USBMODE 0x68 /* USB Device mode */
+#define USBMODE_SDIS (1<<3) /* Stream disable */
+#define USBMODE_BE (1<<2) /* BE/LE endianness select */
+#define USBMODE_CM_HC (3<<0) /* host controller mode */
+#define USBMODE_CM_IDLE (0<<0) /* idle state */
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console. (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+ u32 control;
+#define DBGP_OWNER (1<<30)
+#define DBGP_ENABLED (1<<28)
+#define DBGP_DONE (1<<16)
+#define DBGP_INUSE (1<<10)
+#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
+# define DBGP_ERR_BAD 1
+# define DBGP_ERR_SIGNAL 2
+#define DBGP_ERROR (1<<6)
+#define DBGP_GO (1<<5)
+#define DBGP_OUT (1<<4)
+#define DBGP_LEN(x) (((x)>>0)&0x0f)
+ u32 pids;
+#define DBGP_PID_GET(x) (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
+ u32 data03;
+ u32 data47;
+ u32 address;
+#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
+} __attribute__ ((packed));
+
+#endif /* __LINUX_USB_EHCI_DEF_H */
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 1cbd0a7db4e..2f1113467f7 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc);
extern int unbind_con_driver(const struct consw *csw, int first, int last,
int deflt);
-int vty_init(void);
+int vty_init(const struct file_operations *console_fops);
/*
* vc_screen.c shares this temporary buffer with the console write code so that
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index a6bb94530cf..9909774eb99 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -40,11 +40,12 @@
#include <linux/net.h>
#include <linux/skbuff.h>
#include <net/netlabel.h>
+#include <asm/atomic.h>
/* known doi values */
#define CIPSO_V4_DOI_UNKNOWN 0x00000000
-/* tag types */
+/* standard tag types */
#define CIPSO_V4_TAG_INVALID 0
#define CIPSO_V4_TAG_RBITMAP 1
#define CIPSO_V4_TAG_ENUM 2
@@ -52,10 +53,14 @@
#define CIPSO_V4_TAG_PBITMAP 6
#define CIPSO_V4_TAG_FREEFORM 7
+/* non-standard tag types (tags > 127) */
+#define CIPSO_V4_TAG_LOCAL 128
+
/* doi mapping types */
#define CIPSO_V4_MAP_UNKNOWN 0
-#define CIPSO_V4_MAP_STD 1
+#define CIPSO_V4_MAP_TRANS 1
#define CIPSO_V4_MAP_PASS 2
+#define CIPSO_V4_MAP_LOCAL 3
/* limits */
#define CIPSO_V4_MAX_REM_LVLS 255
@@ -79,10 +84,9 @@ struct cipso_v4_doi {
} map;
u8 tags[CIPSO_V4_TAG_MAXCNT];
- u32 valid;
+ atomic_t refcount;
struct list_head list;
struct rcu_head rcu;
- struct list_head dom_list;
};
/* Standard CIPSO mapping table */
@@ -128,25 +132,26 @@ extern int cipso_v4_rbm_strictvalid;
#ifdef CONFIG_NETLABEL
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
-int cipso_v4_doi_remove(u32 doi,
- struct netlbl_audit *audit_info,
- void (*callback) (struct rcu_head * head));
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def);
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info);
struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def);
int cipso_v4_doi_walk(u32 *skip_cnt,
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
void *cb_arg);
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain);
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
- const char *domain);
#else
static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
{
return -ENOSYS;
}
+static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
+{
+ return;
+}
+
static inline int cipso_v4_doi_remove(u32 doi,
- struct netlbl_audit *audit_info,
- void (*callback) (struct rcu_head * head))
+ struct netlbl_audit *audit_info)
{
return 0;
}
@@ -206,10 +211,15 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
int cipso_v4_sock_setattr(struct sock *sk,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr);
+void cipso_v4_sock_delattr(struct sock *sk);
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_delattr(struct sk_buff *skb);
int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
struct netlbl_lsm_secattr *secattr);
-int cipso_v4_validate(unsigned char **option);
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
#else
static inline void cipso_v4_error(struct sk_buff *skb,
int error,
@@ -225,19 +235,36 @@ static inline int cipso_v4_sock_setattr(struct sock *sk,
return -ENOSYS;
}
+static inline void cipso_v4_sock_delattr(struct sock *sk)
+{
+}
+
static inline int cipso_v4_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
+static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+ return -ENOSYS;
+}
+
static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
-static inline int cipso_v4_validate(unsigned char **option)
+static inline int cipso_v4_validate(const struct sk_buff *skb,
+ unsigned char **option)
{
return -ENOSYS;
}
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index e4d2d6baa98..17c442a4514 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -9,7 +9,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* 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
@@ -72,8 +72,10 @@ struct cipso_v4_doi;
/* NetLabel NETLINK protocol version
* 1: initial version
* 2: added static labels for unlabeled connections
+ * 3: network selectors added to the NetLabel/LSM domain mapping and the
+ * CIPSO_V4_MAP_LOCAL CIPSO mapping was added
*/
-#define NETLBL_PROTO_VERSION 2
+#define NETLBL_PROTO_VERSION 3
/* NetLabel NETLINK types/families */
#define NETLBL_NLTYPE_NONE 0
@@ -87,6 +89,8 @@ struct cipso_v4_doi;
#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6"
#define NETLBL_NLTYPE_UNLABELED 5
#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
+#define NETLBL_NLTYPE_ADDRSELECT 6
+#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL"
/*
* NetLabel - Kernel API for accessing the network packet label mappings.
@@ -200,7 +204,7 @@ struct netlbl_lsm_secattr {
u32 type;
char *domain;
struct netlbl_lsm_cache *cache;
- union {
+ struct {
struct {
struct netlbl_lsm_secattr_catmap *cat;
u32 lvl;
@@ -352,12 +356,9 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
int netlbl_cfg_unlbl_add_map(const char *domain,
struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
- struct netlbl_audit *audit_info);
int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
const char *domain,
struct netlbl_audit *audit_info);
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
/*
* LSM security attribute operations
@@ -380,12 +381,19 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
int netlbl_enabled(void);
int netlbl_sock_setattr(struct sock *sk,
const struct netlbl_lsm_secattr *secattr);
+void netlbl_sock_delattr(struct sock *sk);
int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr);
+int netlbl_conn_setattr(struct sock *sk,
+ struct sockaddr *addr,
+ const struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+ u16 family,
+ const struct netlbl_lsm_secattr *secattr);
int netlbl_skbuff_getattr(const struct sk_buff *skb,
u16 family,
struct netlbl_lsm_secattr *secattr);
-void netlbl_skbuff_err(struct sk_buff *skb, int error);
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway);
/*
* LSM label mapping cache operations
@@ -404,22 +412,12 @@ static inline int netlbl_cfg_unlbl_add_map(const char *domain,
{
return -ENOSYS;
}
-static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
- struct netlbl_audit *audit_info)
-{
- return -ENOSYS;
-}
static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
const char *domain,
struct netlbl_audit *audit_info)
{
return -ENOSYS;
}
-static inline int netlbl_cfg_cipsov4_del(u32 doi,
- struct netlbl_audit *audit_info)
-{
- return -ENOSYS;
-}
static inline int netlbl_secattr_catmap_walk(
struct netlbl_lsm_secattr_catmap *catmap,
u32 offset)
@@ -456,18 +454,35 @@ static inline int netlbl_sock_setattr(struct sock *sk,
{
return -ENOSYS;
}
+static inline void netlbl_sock_delattr(struct sock *sk)
+{
+}
static inline int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
+static inline int netlbl_conn_setattr(struct sock *sk,
+ struct sockaddr *addr,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
+ u16 family,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
u16 family,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
-static inline void netlbl_skbuff_err(struct sk_buff *skb, int error)
+static inline void netlbl_skbuff_err(struct sk_buff *skb,
+ int error,
+ int gateway)
{
return;
}
diff --git a/include/sound/core.h b/include/sound/core.h
index e5eec5f7350..35424a971b7 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -43,9 +43,6 @@
#ifdef CONFIG_PCI
struct pci_dev;
#endif
-#ifdef CONFIG_SBUS
-struct sbus_dev;
-#endif
/* device allocation stuff */
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index d787a6b4a10..7ccce94a525 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -37,7 +37,6 @@ struct snd_dma_device {
#ifndef snd_dma_pci_data
#define snd_dma_pci_data(pci) (&(pci)->dev)
#define snd_dma_isa_data() NULL
-#define snd_dma_sbus_data(sbus) ((struct device *)(sbus))
#define snd_dma_continuous_data(x) ((struct device *)(unsigned long)(x))
#endif
@@ -49,7 +48,6 @@ struct snd_dma_device {
#define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
#define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */
#define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */
-#define SNDRV_DMA_TYPE_SBUS 4 /* SBUS continuous */
/*
* info for buffer allocation
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c1b26fcc0b5..ca699a3017f 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -240,6 +240,7 @@ int snd_soc_dapm_sys_add(struct device *dev);
/* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_sync(struct snd_soc_codec *codec);
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
deleted file mode 100644
index fe43b0f3c86..00000000000
--- a/include/xen/balloon.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/******************************************************************************
- * balloon.h
- *
- * Xen balloon driver - enables returning/claiming memory to/from Xen.
- *
- * Copyright (c) 2003, B Dragovic
- * Copyright (c) 2003-2004, M Williamson, K Fraser
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef __XEN_BALLOON_H__
-#define __XEN_BALLOON_H__
-
-#include <linux/spinlock.h>
-
-#if 0
-/*
- * Inform the balloon driver that it should allow some slop for device-driver
- * memory activities.
- */
-void balloon_update_driver_allowance(long delta);
-
-/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */
-struct page **alloc_empty_pages_and_pagevec(int nr_pages);
-void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages);
-
-void balloon_release_driver_page(struct page *page);
-
-/*
- * Prevent the balloon driver from changing the memory reservation during
- * a driver critical region.
- */
-extern spinlock_t balloon_lock;
-#define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags)
-#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
-#endif
-
-#endif /* __XEN_BALLOON_H__ */
diff --git a/include/xen/events.h b/include/xen/events.h
index 4680ff3fbc9..0d5f1adc036 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -46,6 +46,8 @@ extern void xen_irq_resume(void);
/* Clear an irq's pending state, in preparation for polling on it */
void xen_clear_irq_pending(int irq);
+void xen_set_irq_pending(int irq);
+bool xen_test_irq_pending(int irq);
/* Poll waiting for an irq to become pending. In the usual case, the
irq will be disabled so it won't deliver an interrupt. */
diff --git a/init/Kconfig b/init/Kconfig
index c11da38837e..8a8e2d00c40 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -779,16 +779,6 @@ config MARKERS
source "arch/Kconfig"
-config PROC_PAGE_MONITOR
- default y
- depends on PROC_FS && MMU
- bool "Enable /proc page monitoring" if EMBEDDED
- help
- Various /proc files exist to monitor process memory utilization:
- /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
- /proc/kpagecount, and /proc/kpageflags. Disabling these
- interfaces will reduce the size of the kernel by approximately 4kb.
-
endmenu # General setup
config HAVE_GENERIC_DMA_COHERENT
diff --git a/kernel/acct.c b/kernel/acct.c
index dd68b905941..f6006a60df5 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct,
#endif
spin_lock_irq(&current->sighand->siglock);
- tty = current->signal->tty;
+ tty = current->signal->tty; /* Safe as we hold the siglock */
ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 59cedfb040e..cf5bc2f5f9c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -246,8 +246,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
unsigned n;
if (unlikely(!ctx))
return 0;
-
n = ctx->major;
+
switch (audit_classify_syscall(ctx->arch, n)) {
case 0: /* native */
if ((mask & AUDIT_PERM_WRITE) &&
@@ -1204,13 +1204,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
(context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
context->return_code);
- mutex_lock(&tty_mutex);
- read_lock(&tasklist_lock);
+ spin_lock_irq(&tsk->sighand->siglock);
if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
tty = tsk->signal->tty->name;
else
tty = "(none)";
- read_unlock(&tasklist_lock);
+ spin_unlock_irq(&tsk->sighand->siglock);
+
audit_log_format(ab,
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
" ppid=%d pid=%d auid=%u uid=%u gid=%u"
@@ -1230,7 +1230,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
context->egid, context->sgid, context->fsgid, tty,
tsk->sessionid);
- mutex_unlock(&tty_mutex);
audit_log_task_info(ab, tsk);
if (context->filterkey) {
diff --git a/kernel/fork.c b/kernel/fork.c
index 7ce2ebe8479..30de644a40c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
sig->leader = 0; /* session leadership doesn't inherit */
sig->tty_old_pgrp = NULL;
+ sig->tty = NULL;
sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
sig->gtime = cputime_zero;
@@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
void __cleanup_signal(struct signal_struct *sig)
{
exit_thread_group_keys(sig);
+ tty_kref_put(sig->tty);
kmem_cache_free(signal_cachep, sig);
}
@@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->nsproxy->pid_ns->child_reaper = p;
p->signal->leader_pid = pid;
- p->signal->tty = current->signal->tty;
+ tty_kref_put(p->signal->tty);
+ p->signal->tty = tty_kref_get(current->signal->tty);
set_task_pgrp(p, task_pgrp_nr(current));
set_task_session(p, task_session_nr(current));
attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
diff --git a/kernel/printk.c b/kernel/printk.c
index b51b1567bb5..a430fd04008 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1291,22 +1291,6 @@ static int __init disable_boot_consoles(void)
}
late_initcall(disable_boot_consoles);
-/**
- * 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
- * really needed.
- */
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
- if (tty && tty->ops->write)
- tty->ops->write(tty, msg, strlen(msg));
- return;
-}
-
#if defined CONFIG_PRINTK
/*
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index bbe6b31c3c5..ad958c1ec70 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -333,12 +333,10 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
unsigned long flags;
int num_threads = 1;
- rcu_read_lock();
if (lock_task_sighand(p, &flags)) {
num_threads = atomic_read(&p->signal->count);
unlock_task_sighand(p, &flags);
}
- rcu_read_unlock();
SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
SEQ_printf(m,
diff --git a/kernel/sys.c b/kernel/sys.c
index 038a7bc0901..234d9454294 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1060,9 +1060,7 @@ asmlinkage long sys_setsid(void)
group_leader->signal->leader = 1;
__set_special_pids(sid);
- spin_lock(&group_leader->sighand->siglock);
- group_leader->signal->tty = NULL;
- spin_unlock(&group_leader->sighand->siglock);
+ proc_clear_tty(group_leader);
err = session;
out:
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 50ec0886fa3..c468c3c6dfc 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -80,7 +80,6 @@ extern int pid_max_min, pid_max_max;
extern int sysctl_drop_caches;
extern int percpu_pagelist_fraction;
extern int compat_log;
-extern int maps_protect;
extern int latencytop_enabled;
extern int sysctl_nr_open_min, sysctl_nr_open_max;
#ifdef CONFIG_RCU_TORTURE_TEST
@@ -118,10 +117,8 @@ extern char modprobe_path[];
extern int sg_big_buff;
#endif
-#ifdef __sparc__
-extern char reboot_command [];
-extern int stop_a_enabled;
-extern int scons_pwroff;
+#ifdef CONFIG_SPARC
+#include <asm/system.h>
#endif
#ifdef __hppa__
@@ -415,7 +412,7 @@ static struct ctl_table kern_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
{
.ctl_name = KERN_SPARC_REBOOT,
.procname = "reboot-cmd",
@@ -810,16 +807,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
-#ifdef CONFIG_PROC_FS
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "maps_protect",
- .data = &maps_protect,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
-#endif
{
.ctl_name = CTL_UNNUMBERED,
.procname = "poweroff_cmd",
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ce697e0b319..aa81d284844 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -495,6 +495,15 @@ config DEBUG_VM
If unsure, say N.
+config DEBUG_VIRTUAL
+ bool "Debug VM translations"
+ depends on DEBUG_KERNEL && X86
+ help
+ Enable some costly sanity checks in virtual to page code. This can
+ catch mistakes with virt_to_page() and friends.
+
+ If unsure, say N.
+
config DEBUG_WRITECOUNT
bool "Debug filesystem writers count"
depends on DEBUG_KERNEL
diff --git a/lib/cmdline.c b/lib/cmdline.c
index 5ba8a942a47..f5f3ad8b62f 100644
--- a/lib/cmdline.c
+++ b/lib/cmdline.c
@@ -126,7 +126,7 @@ char *get_options(const char *str, int nints, int *ints)
* megabyte, or one gigabyte, respectively.
*/
-unsigned long long memparse(char *ptr, char **retptr)
+unsigned long long memparse(const char *ptr, char **retptr)
{
char *endptr; /* local pointer to end of parsed string */
diff --git a/lib/parser.c b/lib/parser.c
index 4f0cbc03e0e..b00d02059a5 100644
--- a/lib/parser.c
+++ b/lib/parser.c
@@ -100,7 +100,7 @@ static int match_one(char *s, const char *p, substring_t args[])
* format identifiers which will be taken into account when matching the
* tokens, and whose locations will be returned in the @args array.
*/
-int match_token(char *s, match_table_t table, substring_t args[])
+int match_token(char *s, const match_table_t table, substring_t args[])
{
const struct match_token *p;
diff --git a/mm/shmem.c b/mm/shmem.c
index 04fb4f1ab88..bf66d0191ba 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -50,14 +50,12 @@
#include <linux/migrate.h>
#include <linux/highmem.h>
#include <linux/seq_file.h>
+#include <linux/magic.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <asm/pgtable.h>
-/* This magic number is used in glibc for posix shared memory */
-#define TMPFS_MAGIC 0x01021994
-
#define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
#define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 85b9a0d2c87..bba06c41fc5 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -180,6 +180,13 @@ struct page *vmalloc_to_page(const void *vmalloc_addr)
pmd_t *pmd;
pte_t *ptep, pte;
+ /*
+ * XXX we might need to change this if we add VIRTUAL_BUG_ON for
+ * architectures that do not vmalloc module space
+ */
+ VIRTUAL_BUG_ON(!is_vmalloc_addr(vmalloc_addr) &&
+ !is_module_address(addr));
+
if (!pgd_none(*pgd)) {
pud = pud_offset(pgd, addr);
if (!pud_none(*pud)) {
diff --git a/net/9p/client.c b/net/9p/client.c
index 10e320307ec..e053e06028a 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -52,7 +52,7 @@ enum {
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_msize, "msize=%u"},
{Opt_legacy, "noextend"},
{Opt_trans, "trans=%s"},
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index d652baf5ff9..6dabbdb6665 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -86,7 +86,7 @@ enum {
Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_port, "port=%u"},
{Opt_rfdno, "rfdno=%u"},
{Opt_wfdno, "wfdno=%u"},
diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c
index 1f49afcd8e8..86234923a3b 100644
--- a/net/core/skb_dma_map.c
+++ b/net/core/skb_dma_map.c
@@ -35,7 +35,7 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb,
return 0;
unwind:
- while (i-- >= 0) {
+ while (--i >= 0) {
skb_frag_t *fp = &sp->frags[i];
dma_unmap_page(dev, sp->dma_maps[i + 1],
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 2c0e4572cc9..490e035c6d9 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -13,7 +13,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* 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
@@ -47,17 +47,7 @@
#include <asm/bug.h>
#include <asm/unaligned.h>
-struct cipso_v4_domhsh_entry {
- char *domain;
- u32 valid;
- struct list_head list;
- struct rcu_head rcu;
-};
-
/* List of available DOI definitions */
-/* XXX - Updates should be minimal so having a single lock for the
- * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
- * okay. */
/* XXX - This currently assumes a minimal number of different DOIs in use,
* if in practice there are a lot of different DOIs this list should
* probably be turned into a hash table or something similar so we
@@ -119,6 +109,19 @@ int cipso_v4_rbm_strictvalid = 1;
* be omitted. */
#define CIPSO_V4_TAG_RNG_CAT_MAX 8
+/* Base length of the local tag (non-standard tag).
+ * Tag definition (may change between kernel versions)
+ *
+ * 0 8 16 24 32
+ * +----------+----------+----------+----------+
+ * | 10000000 | 00000110 | 32-bit secid value |
+ * +----------+----------+----------+----------+
+ * | in (host byte order)|
+ * +----------+----------+
+ *
+ */
+#define CIPSO_V4_TAG_LOC_BLEN 6
+
/*
* Helper Functions
*/
@@ -194,25 +197,6 @@ static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
}
/**
- * cipso_v4_doi_domhsh_free - Frees a domain list entry
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to a domain list entry can be released
- * safely.
- *
- */
-static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
-{
- struct cipso_v4_domhsh_entry *ptr;
-
- ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
- kfree(ptr->domain);
- kfree(ptr);
-}
-
-/**
* cipso_v4_cache_entry_free - Frees a cache entry
* @entry: the entry to free
*
@@ -457,7 +441,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
struct cipso_v4_doi *iter;
list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
- if (iter->doi == doi && iter->valid)
+ if (iter->doi == doi && atomic_read(&iter->refcount))
return iter;
return NULL;
}
@@ -496,14 +480,17 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
if (doi_def->type != CIPSO_V4_MAP_PASS)
return -EINVAL;
break;
+ case CIPSO_V4_TAG_LOCAL:
+ if (doi_def->type != CIPSO_V4_MAP_LOCAL)
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
}
- doi_def->valid = 1;
+ atomic_set(&doi_def->refcount, 1);
INIT_RCU_HEAD(&doi_def->rcu);
- INIT_LIST_HEAD(&doi_def->dom_list);
spin_lock(&cipso_v4_doi_list_lock);
if (cipso_v4_doi_search(doi_def->doi) != NULL)
@@ -519,59 +506,129 @@ doi_add_failure:
}
/**
+ * cipso_v4_doi_free - Frees a DOI definition
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function frees all of the memory associated with a DOI definition.
+ *
+ */
+void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
+{
+ if (doi_def == NULL)
+ return;
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_TRANS:
+ kfree(doi_def->map.std->lvl.cipso);
+ kfree(doi_def->map.std->lvl.local);
+ kfree(doi_def->map.std->cat.cipso);
+ kfree(doi_def->map.std->cat.local);
+ break;
+ }
+ kfree(doi_def);
+}
+
+/**
+ * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to the DOI definition can be released
+ * safely.
+ *
+ */
+static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
+{
+ struct cipso_v4_doi *doi_def;
+
+ doi_def = container_of(entry, struct cipso_v4_doi, rcu);
+ cipso_v4_doi_free(doi_def);
+}
+
+/**
* cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
* @doi: the DOI value
* @audit_secid: the LSM secid to use in the audit message
- * @callback: the DOI cleanup/free callback
*
* Description:
- * Removes a DOI definition from the CIPSO engine, @callback is called to
- * free any memory. The NetLabel routines will be called to release their own
- * LSM domain mappings as well as our own domain list. Returns zero on
- * success and negative values on failure.
+ * Removes a DOI definition from the CIPSO engine. The NetLabel routines will
+ * be called to release their own LSM domain mappings as well as our own
+ * domain list. Returns zero on success and negative values on failure.
*
*/
-int cipso_v4_doi_remove(u32 doi,
- struct netlbl_audit *audit_info,
- void (*callback) (struct rcu_head * head))
+int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
{
struct cipso_v4_doi *doi_def;
- struct cipso_v4_domhsh_entry *dom_iter;
spin_lock(&cipso_v4_doi_list_lock);
doi_def = cipso_v4_doi_search(doi);
- if (doi_def != NULL) {
- doi_def->valid = 0;
- list_del_rcu(&doi_def->list);
+ if (doi_def == NULL) {
spin_unlock(&cipso_v4_doi_list_lock);
- rcu_read_lock();
- list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
- if (dom_iter->valid)
- netlbl_cfg_map_del(dom_iter->domain,
- audit_info);
- rcu_read_unlock();
- cipso_v4_cache_invalidate();
- call_rcu(&doi_def->rcu, callback);
- return 0;
+ return -ENOENT;
+ }
+ if (!atomic_dec_and_test(&doi_def->refcount)) {
+ spin_unlock(&cipso_v4_doi_list_lock);
+ return -EBUSY;
}
+ list_del_rcu(&doi_def->list);
spin_unlock(&cipso_v4_doi_list_lock);
- return -ENOENT;
+ cipso_v4_cache_invalidate();
+ call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
+
+ return 0;
}
/**
- * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
+ * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition
* @doi: the DOI value
*
* Description:
* Searches for a valid DOI definition and if one is found it is returned to
* the caller. Otherwise NULL is returned. The caller must ensure that
- * rcu_read_lock() is held while accessing the returned definition.
+ * rcu_read_lock() is held while accessing the returned definition and the DOI
+ * definition reference count is decremented when the caller is done.
*
*/
struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
{
- return cipso_v4_doi_search(doi);
+ struct cipso_v4_doi *doi_def;
+
+ rcu_read_lock();
+ doi_def = cipso_v4_doi_search(doi);
+ if (doi_def == NULL)
+ goto doi_getdef_return;
+ if (!atomic_inc_not_zero(&doi_def->refcount))
+ doi_def = NULL;
+
+doi_getdef_return:
+ rcu_read_unlock();
+ return doi_def;
+}
+
+/**
+ * cipso_v4_doi_putdef - Releases a reference for the given DOI definition
+ * @doi_def: the DOI definition
+ *
+ * Description:
+ * Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
+ *
+ */
+void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
+{
+ if (doi_def == NULL)
+ return;
+
+ if (!atomic_dec_and_test(&doi_def->refcount))
+ return;
+ spin_lock(&cipso_v4_doi_list_lock);
+ list_del_rcu(&doi_def->list);
+ spin_unlock(&cipso_v4_doi_list_lock);
+
+ cipso_v4_cache_invalidate();
+ call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
}
/**
@@ -597,7 +654,7 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
rcu_read_lock();
list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
- if (iter_doi->valid) {
+ if (atomic_read(&iter_doi->refcount) > 0) {
if (doi_cnt++ < *skip_cnt)
continue;
ret_val = callback(iter_doi, cb_arg);
@@ -613,85 +670,6 @@ doi_walk_return:
return ret_val;
}
-/**
- * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to add
- *
- * Description:
- * Adds the @domain to the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel). This function
- * does allocate memory. Returns zero on success, negative values on failure.
- *
- */
-int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
-{
- struct cipso_v4_domhsh_entry *iter;
- struct cipso_v4_domhsh_entry *new_dom;
-
- new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
- if (new_dom == NULL)
- return -ENOMEM;
- if (domain) {
- new_dom->domain = kstrdup(domain, GFP_KERNEL);
- if (new_dom->domain == NULL) {
- kfree(new_dom);
- return -ENOMEM;
- }
- }
- new_dom->valid = 1;
- INIT_RCU_HEAD(&new_dom->rcu);
-
- spin_lock(&cipso_v4_doi_list_lock);
- list_for_each_entry(iter, &doi_def->dom_list, list)
- if (iter->valid &&
- ((domain != NULL && iter->domain != NULL &&
- strcmp(iter->domain, domain) == 0) ||
- (domain == NULL && iter->domain == NULL))) {
- spin_unlock(&cipso_v4_doi_list_lock);
- kfree(new_dom->domain);
- kfree(new_dom);
- return -EEXIST;
- }
- list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
- spin_unlock(&cipso_v4_doi_list_lock);
-
- return 0;
-}
-
-/**
- * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
- * @doi_def: the DOI definition
- * @domain: the domain to remove
- *
- * Description:
- * Removes the @domain from the DOI specified by @doi_def, this function
- * should only be called by external functions (i.e. NetLabel). Returns zero
- * on success and negative values on error.
- *
- */
-int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
- const char *domain)
-{
- struct cipso_v4_domhsh_entry *iter;
-
- spin_lock(&cipso_v4_doi_list_lock);
- list_for_each_entry(iter, &doi_def->dom_list, list)
- if (iter->valid &&
- ((domain != NULL && iter->domain != NULL &&
- strcmp(iter->domain, domain) == 0) ||
- (domain == NULL && iter->domain == NULL))) {
- iter->valid = 0;
- list_del_rcu(&iter->list);
- spin_unlock(&cipso_v4_doi_list_lock);
- call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
- return 0;
- }
- spin_unlock(&cipso_v4_doi_list_lock);
-
- return -ENOENT;
-}
-
/*
* Label Mapping Functions
*/
@@ -712,7 +690,7 @@ static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
return 0;
- case CIPSO_V4_MAP_STD:
+ case CIPSO_V4_MAP_TRANS:
if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
return 0;
break;
@@ -741,7 +719,7 @@ static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
case CIPSO_V4_MAP_PASS:
*net_lvl = host_lvl;
return 0;
- case CIPSO_V4_MAP_STD:
+ case CIPSO_V4_MAP_TRANS:
if (host_lvl < doi_def->map.std->lvl.local_size &&
doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) {
*net_lvl = doi_def->map.std->lvl.local[host_lvl];
@@ -775,7 +753,7 @@ static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
case CIPSO_V4_MAP_PASS:
*host_lvl = net_lvl;
return 0;
- case CIPSO_V4_MAP_STD:
+ case CIPSO_V4_MAP_TRANS:
map_tbl = doi_def->map.std;
if (net_lvl < map_tbl->lvl.cipso_size &&
map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
@@ -812,7 +790,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
return 0;
- case CIPSO_V4_MAP_STD:
+ case CIPSO_V4_MAP_TRANS:
cipso_cat_size = doi_def->map.std->cat.cipso_size;
cipso_array = doi_def->map.std->cat.cipso;
for (;;) {
@@ -860,7 +838,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
u32 host_cat_size = 0;
u32 *host_cat_array = NULL;
- if (doi_def->type == CIPSO_V4_MAP_STD) {
+ if (doi_def->type == CIPSO_V4_MAP_TRANS) {
host_cat_size = doi_def->map.std->cat.local_size;
host_cat_array = doi_def->map.std->cat.local;
}
@@ -875,7 +853,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
case CIPSO_V4_MAP_PASS:
net_spot = host_spot;
break;
- case CIPSO_V4_MAP_STD:
+ case CIPSO_V4_MAP_TRANS:
if (host_spot >= host_cat_size)
return -EPERM;
net_spot = host_cat_array[host_spot];
@@ -921,7 +899,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
u32 net_cat_size = 0;
u32 *net_cat_array = NULL;
- if (doi_def->type == CIPSO_V4_MAP_STD) {
+ if (doi_def->type == CIPSO_V4_MAP_TRANS) {
net_cat_size = doi_def->map.std->cat.cipso_size;
net_cat_array = doi_def->map.std->cat.cipso;
}
@@ -941,7 +919,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
case CIPSO_V4_MAP_PASS:
host_spot = net_spot;
break;
- case CIPSO_V4_MAP_STD:
+ case CIPSO_V4_MAP_TRANS:
if (net_spot >= net_cat_size)
return -EPERM;
host_spot = net_cat_array[net_spot];
@@ -1277,7 +1255,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
} else
tag_len = 4;
- buffer[0] = 0x01;
+ buffer[0] = CIPSO_V4_TAG_RBITMAP;
buffer[1] = tag_len;
buffer[3] = level;
@@ -1373,7 +1351,7 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
} else
tag_len = 4;
- buffer[0] = 0x02;
+ buffer[0] = CIPSO_V4_TAG_ENUM;
buffer[1] = tag_len;
buffer[3] = level;
@@ -1469,7 +1447,7 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
} else
tag_len = 4;
- buffer[0] = 0x05;
+ buffer[0] = CIPSO_V4_TAG_RANGE;
buffer[1] = tag_len;
buffer[3] = level;
@@ -1523,6 +1501,54 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
}
/**
+ * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard)
+ * @doi_def: the DOI definition
+ * @secattr: the security attributes
+ * @buffer: the option buffer
+ * @buffer_len: length of buffer in bytes
+ *
+ * Description:
+ * Generate a CIPSO option using the local tag. Returns the size of the tag
+ * on success, negative values on failure.
+ *
+ */
+static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr,
+ unsigned char *buffer,
+ u32 buffer_len)
+{
+ if (!(secattr->flags & NETLBL_SECATTR_SECID))
+ return -EPERM;
+
+ buffer[0] = CIPSO_V4_TAG_LOCAL;
+ buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
+ *(u32 *)&buffer[2] = secattr->attr.secid;
+
+ return CIPSO_V4_TAG_LOC_BLEN;
+}
+
+/**
+ * cipso_v4_parsetag_loc - Parse a CIPSO local tag
+ * @doi_def: the DOI definition
+ * @tag: the CIPSO tag
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse a CIPSO local tag and return the security attributes in @secattr.
+ * Return zero on success, negatives values on failure.
+ *
+ */
+static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
+ const unsigned char *tag,
+ struct netlbl_lsm_secattr *secattr)
+{
+ secattr->attr.secid = *(u32 *)&tag[2];
+ secattr->flags |= NETLBL_SECATTR_SECID;
+
+ return 0;
+}
+
+/**
* cipso_v4_validate - Validate a CIPSO option
* @option: the start of the option, on error it is set to point to the error
*
@@ -1541,7 +1567,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
* that is unrecognized."
*
*/
-int cipso_v4_validate(unsigned char **option)
+int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
{
unsigned char *opt = *option;
unsigned char *tag;
@@ -1566,7 +1592,7 @@ int cipso_v4_validate(unsigned char **option)
goto validate_return_locked;
}
- opt_iter = 6;
+ opt_iter = CIPSO_V4_HDR_LEN;
tag = opt + opt_iter;
while (opt_iter < opt_len) {
for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
@@ -1584,7 +1610,7 @@ int cipso_v4_validate(unsigned char **option)
switch (tag[0]) {
case CIPSO_V4_TAG_RBITMAP:
- if (tag_len < 4) {
+ if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
err_offset = opt_iter + 1;
goto validate_return_locked;
}
@@ -1602,7 +1628,7 @@ int cipso_v4_validate(unsigned char **option)
err_offset = opt_iter + 3;
goto validate_return_locked;
}
- if (tag_len > 4 &&
+ if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
cipso_v4_map_cat_rbm_valid(doi_def,
&tag[4],
tag_len - 4) < 0) {
@@ -1612,7 +1638,7 @@ int cipso_v4_validate(unsigned char **option)
}
break;
case CIPSO_V4_TAG_ENUM:
- if (tag_len < 4) {
+ if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
err_offset = opt_iter + 1;
goto validate_return_locked;
}
@@ -1622,7 +1648,7 @@ int cipso_v4_validate(unsigned char **option)
err_offset = opt_iter + 3;
goto validate_return_locked;
}
- if (tag_len > 4 &&
+ if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
cipso_v4_map_cat_enum_valid(doi_def,
&tag[4],
tag_len - 4) < 0) {
@@ -1631,7 +1657,7 @@ int cipso_v4_validate(unsigned char **option)
}
break;
case CIPSO_V4_TAG_RANGE:
- if (tag_len < 4) {
+ if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
err_offset = opt_iter + 1;
goto validate_return_locked;
}
@@ -1641,7 +1667,7 @@ int cipso_v4_validate(unsigned char **option)
err_offset = opt_iter + 3;
goto validate_return_locked;
}
- if (tag_len > 4 &&
+ if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
cipso_v4_map_cat_rng_valid(doi_def,
&tag[4],
tag_len - 4) < 0) {
@@ -1649,6 +1675,19 @@ int cipso_v4_validate(unsigned char **option)
goto validate_return_locked;
}
break;
+ case CIPSO_V4_TAG_LOCAL:
+ /* This is a non-standard tag that we only allow for
+ * local connections, so if the incoming interface is
+ * not the loopback device drop the packet. */
+ if (!(skb->dev->flags & IFF_LOOPBACK)) {
+ err_offset = opt_iter;
+ goto validate_return_locked;
+ }
+ if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
+ err_offset = opt_iter + 1;
+ goto validate_return_locked;
+ }
+ break;
default:
err_offset = opt_iter;
goto validate_return_locked;
@@ -1704,48 +1743,27 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
}
/**
- * cipso_v4_sock_setattr - Add a CIPSO option to a socket
- * @sk: the socket
+ * cipso_v4_genopt - Generate a CIPSO option
+ * @buf: the option buffer
+ * @buf_len: the size of opt_buf
* @doi_def: the CIPSO DOI to use
- * @secattr: the specific security attributes of the socket
+ * @secattr: the security attributes
*
* Description:
- * Set the CIPSO option on the given socket using the DOI definition and
- * security attributes passed to the function. This function requires
- * exclusive access to @sk, which means it either needs to be in the
- * process of being created or locked. Returns zero on success and negative
- * values on failure.
+ * Generate a CIPSO option using the DOI definition and security attributes
+ * passed to the function. Returns the length of the option on success and
+ * negative values on failure.
*
*/
-int cipso_v4_sock_setattr(struct sock *sk,
- const struct cipso_v4_doi *doi_def,
- const struct netlbl_lsm_secattr *secattr)
+static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr)
{
- int ret_val = -EPERM;
+ int ret_val;
u32 iter;
- unsigned char *buf;
- u32 buf_len = 0;
- u32 opt_len;
- struct ip_options *opt = NULL;
- struct inet_sock *sk_inet;
- struct inet_connection_sock *sk_conn;
- /* In the case of sock_create_lite(), the sock->sk field is not
- * defined yet but it is not a problem as the only users of these
- * "lite" PF_INET sockets are functions which do an accept() call
- * afterwards so we will label the socket as part of the accept(). */
- if (sk == NULL)
- return 0;
-
- /* We allocate the maximum CIPSO option size here so we are probably
- * being a little wasteful, but it makes our life _much_ easier later
- * on and after all we are only talking about 40 bytes. */
- buf_len = CIPSO_V4_OPT_LEN_MAX;
- buf = kmalloc(buf_len, GFP_ATOMIC);
- if (buf == NULL) {
- ret_val = -ENOMEM;
- goto socket_setattr_failure;
- }
+ if (buf_len <= CIPSO_V4_HDR_LEN)
+ return -ENOSPC;
/* XXX - This code assumes only one tag per CIPSO option which isn't
* really a good assumption to make but since we only support the MAC
@@ -1772,9 +1790,14 @@ int cipso_v4_sock_setattr(struct sock *sk,
&buf[CIPSO_V4_HDR_LEN],
buf_len - CIPSO_V4_HDR_LEN);
break;
+ case CIPSO_V4_TAG_LOCAL:
+ ret_val = cipso_v4_gentag_loc(doi_def,
+ secattr,
+ &buf[CIPSO_V4_HDR_LEN],
+ buf_len - CIPSO_V4_HDR_LEN);
+ break;
default:
- ret_val = -EPERM;
- goto socket_setattr_failure;
+ return -EPERM;
}
iter++;
@@ -1782,9 +1805,58 @@ int cipso_v4_sock_setattr(struct sock *sk,
iter < CIPSO_V4_TAG_MAXCNT &&
doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
if (ret_val < 0)
- goto socket_setattr_failure;
+ return ret_val;
cipso_v4_gentag_hdr(doi_def, buf, ret_val);
- buf_len = CIPSO_V4_HDR_LEN + ret_val;
+ return CIPSO_V4_HDR_LEN + ret_val;
+}
+
+/**
+ * cipso_v4_sock_setattr - Add a CIPSO option to a socket
+ * @sk: the socket
+ * @doi_def: the CIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
+ *
+ * Description:
+ * Set the CIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function. This function requires
+ * exclusive access to @sk, which means it either needs to be in the
+ * process of being created or locked. Returns zero on success and negative
+ * values on failure.
+ *
+ */
+int cipso_v4_sock_setattr(struct sock *sk,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val = -EPERM;
+ unsigned char *buf = NULL;
+ u32 buf_len;
+ u32 opt_len;
+ struct ip_options *opt = NULL;
+ struct inet_sock *sk_inet;
+ struct inet_connection_sock *sk_conn;
+
+ /* In the case of sock_create_lite(), the sock->sk field is not
+ * defined yet but it is not a problem as the only users of these
+ * "lite" PF_INET sockets are functions which do an accept() call
+ * afterwards so we will label the socket as part of the accept(). */
+ if (sk == NULL)
+ return 0;
+
+ /* We allocate the maximum CIPSO option size here so we are probably
+ * being a little wasteful, but it makes our life _much_ easier later
+ * on and after all we are only talking about 40 bytes. */
+ buf_len = CIPSO_V4_OPT_LEN_MAX;
+ buf = kmalloc(buf_len, GFP_ATOMIC);
+ if (buf == NULL) {
+ ret_val = -ENOMEM;
+ goto socket_setattr_failure;
+ }
+
+ ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+ if (ret_val < 0)
+ goto socket_setattr_failure;
+ buf_len = ret_val;
/* We can't use ip_options_get() directly because it makes a call to
* ip_options_get_alloc() which allocates memory with GFP_KERNEL and
@@ -1822,6 +1894,80 @@ socket_setattr_failure:
}
/**
+ * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Removes the CIPSO option from a socket, if present.
+ *
+ */
+void cipso_v4_sock_delattr(struct sock *sk)
+{
+ u8 hdr_delta;
+ struct ip_options *opt;
+ struct inet_sock *sk_inet;
+
+ sk_inet = inet_sk(sk);
+ opt = sk_inet->opt;
+ if (opt == NULL || opt->cipso == 0)
+ return;
+
+ if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
+ u8 cipso_len;
+ u8 cipso_off;
+ unsigned char *cipso_ptr;
+ int iter;
+ int optlen_new;
+
+ cipso_off = opt->cipso - sizeof(struct iphdr);
+ cipso_ptr = &opt->__data[cipso_off];
+ cipso_len = cipso_ptr[1];
+
+ if (opt->srr > opt->cipso)
+ opt->srr -= cipso_len;
+ if (opt->rr > opt->cipso)
+ opt->rr -= cipso_len;
+ if (opt->ts > opt->cipso)
+ opt->ts -= cipso_len;
+ if (opt->router_alert > opt->cipso)
+ opt->router_alert -= cipso_len;
+ opt->cipso = 0;
+
+ memmove(cipso_ptr, cipso_ptr + cipso_len,
+ opt->optlen - cipso_off - cipso_len);
+
+ /* determining the new total option length is tricky because of
+ * the padding necessary, the only thing i can think to do at
+ * this point is walk the options one-by-one, skipping the
+ * padding at the end to determine the actual option size and
+ * from there we can determine the new total option length */
+ iter = 0;
+ optlen_new = 0;
+ while (iter < opt->optlen)
+ if (opt->__data[iter] != IPOPT_NOP) {
+ iter += opt->__data[iter + 1];
+ optlen_new = iter;
+ } else
+ iter++;
+ hdr_delta = opt->optlen;
+ opt->optlen = (optlen_new + 3) & ~3;
+ hdr_delta -= opt->optlen;
+ } else {
+ /* only the cipso option was present on the socket so we can
+ * remove the entire option struct */
+ sk_inet->opt = NULL;
+ hdr_delta = opt->optlen;
+ kfree(opt);
+ }
+
+ if (sk_inet->is_icsk && hdr_delta > 0) {
+ struct inet_connection_sock *sk_conn = inet_csk(sk);
+ sk_conn->icsk_ext_hdr_len -= hdr_delta;
+ sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+ }
+}
+
+/**
* cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
* @cipso: the CIPSO v4 option
* @secattr: the security attributes
@@ -1859,6 +2005,9 @@ static int cipso_v4_getattr(const unsigned char *cipso,
case CIPSO_V4_TAG_RANGE:
ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
break;
+ case CIPSO_V4_TAG_LOCAL:
+ ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
+ break;
}
if (ret_val == 0)
secattr->type = NETLBL_NLTYPE_CIPSOV4;
@@ -1893,6 +2042,123 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
}
/**
+ * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Set the CIPSO option on the given packet based on the security attributes.
+ * Returns a pointer to the IP header on success and NULL on failure.
+ *
+ */
+int cipso_v4_skbuff_setattr(struct sk_buff *skb,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val;
+ struct iphdr *iph;
+ struct ip_options *opt = &IPCB(skb)->opt;
+ unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
+ u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
+ u32 opt_len;
+ int len_delta;
+
+ buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
+ if (buf_len < 0)
+ return buf_len;
+ opt_len = (buf_len + 3) & ~3;
+
+ /* we overwrite any existing options to ensure that we have enough
+ * room for the CIPSO option, the reason is that we _need_ to guarantee
+ * that the security label is applied to the packet - we do the same
+ * thing when using the socket options and it hasn't caused a problem,
+ * if we need to we can always revisit this choice later */
+
+ len_delta = opt_len - opt->optlen;
+ /* if we don't ensure enough headroom we could panic on the skb_push()
+ * call below so make sure we have enough, we are also "mangling" the
+ * packet so we should probably do a copy-on-write call anyway */
+ ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
+ if (ret_val < 0)
+ return ret_val;
+
+ if (len_delta > 0) {
+ /* we assume that the header + opt->optlen have already been
+ * "pushed" in ip_options_build() or similar */
+ iph = ip_hdr(skb);
+ skb_push(skb, len_delta);
+ memmove((char *)iph - len_delta, iph, iph->ihl << 2);
+ skb_reset_network_header(skb);
+ iph = ip_hdr(skb);
+ } else if (len_delta < 0) {
+ iph = ip_hdr(skb);
+ memset(iph + 1, IPOPT_NOP, opt->optlen);
+ } else
+ iph = ip_hdr(skb);
+
+ if (opt->optlen > 0)
+ memset(opt, 0, sizeof(*opt));
+ opt->optlen = opt_len;
+ opt->cipso = sizeof(struct iphdr);
+ opt->is_changed = 1;
+
+ /* we have to do the following because we are being called from a
+ * netfilter hook which means the packet already has had the header
+ * fields populated and the checksum calculated - yes this means we
+ * are doing more work than needed but we do it to keep the core
+ * stack clean and tidy */
+ memcpy(iph + 1, buf, buf_len);
+ if (opt_len > buf_len)
+ memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
+ if (len_delta != 0) {
+ iph->ihl = 5 + (opt_len >> 2);
+ iph->tot_len = htons(skb->len);
+ }
+ ip_send_check(iph);
+
+ return 0;
+}
+
+/**
+ * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
+ * @skb: the packet
+ *
+ * Description:
+ * Removes any and all CIPSO options from the given packet. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int cipso_v4_skbuff_delattr(struct sk_buff *skb)
+{
+ int ret_val;
+ struct iphdr *iph;
+ struct ip_options *opt = &IPCB(skb)->opt;
+ unsigned char *cipso_ptr;
+
+ if (opt->cipso == 0)
+ return 0;
+
+ /* since we are changing the packet we should make a copy */
+ ret_val = skb_cow(skb, skb_headroom(skb));
+ if (ret_val < 0)
+ return ret_val;
+
+ /* the easiest thing to do is just replace the cipso option with noop
+ * options since we don't change the size of the packet, although we
+ * still need to recalculate the checksum */
+
+ iph = ip_hdr(skb);
+ cipso_ptr = (unsigned char *)iph + opt->cipso;
+ memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
+ opt->cipso = 0;
+ opt->is_changed = 1;
+
+ ip_send_check(iph);
+
+ return 0;
+}
+
+/**
* cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
* @skb: the packet
* @secattr: the security attributes
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 05ebce2881e..85c487b8572 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1345,7 +1345,7 @@ out:
static void ipgre_netlink_parms(struct nlattr *data[],
struct ip_tunnel_parm *parms)
{
- memset(parms, 0, sizeof(parms));
+ memset(parms, 0, sizeof(*parms));
parms->iph.protocol = IPPROTO_GRE;
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index be3f18a7a40..2c88da6e786 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -438,7 +438,7 @@ int ip_options_compile(struct net *net,
goto error;
}
opt->cipso = optptr - iph;
- if (cipso_v4_validate(&optptr)) {
+ if (cipso_v4_validate(skb, &optptr)) {
pp_ptr = optptr;
goto error;
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 77e7b014872..cf6b121e1bb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1379,6 +1379,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
return RX_QUEUED;
}
+#ifdef CONFIG_MAC80211_MESH
static ieee80211_rx_result
ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
{
@@ -1453,7 +1454,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
else
return RX_DROP_MONITOR;
}
-
+#endif
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
@@ -1780,8 +1781,10 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
/* must be after MMIC verify so header is counted in MPDU mic */
CALL_RXH(ieee80211_rx_h_remove_qos_control)
CALL_RXH(ieee80211_rx_h_amsdu)
+#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
+#endif
CALL_RXH(ieee80211_rx_h_data)
CALL_RXH(ieee80211_rx_h_ctrl)
CALL_RXH(ieee80211_rx_h_action)
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index de6004de80b..05048e40326 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -2,8 +2,8 @@
# IP Virtual Server configuration
#
menuconfig IP_VS
- tristate "IP virtual server support (EXPERIMENTAL)"
- depends on NETFILTER
+ tristate "IP virtual server support"
+ depends on NET && INET && NETFILTER
---help---
IP Virtual Server support will let you build a high-performance
virtual server based on cluster of two or more real servers. This
diff --git a/net/netfilter/nf_tproxy_core.c b/net/netfilter/nf_tproxy_core.c
index fe34f4bf74c..cdc97f3105a 100644
--- a/net/netfilter/nf_tproxy_core.c
+++ b/net/netfilter/nf_tproxy_core.c
@@ -10,7 +10,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/net.h>
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile
index 8af18c0a47d..ea750e9df65 100644
--- a/net/netlabel/Makefile
+++ b/net/netlabel/Makefile
@@ -5,7 +5,8 @@
#
# base objects
-obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
+obj-y := netlabel_user.o netlabel_kapi.o
+obj-y += netlabel_domainhash.o netlabel_addrlist.o
# management objects
obj-y += netlabel_mgmt.o
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
new file mode 100644
index 00000000000..b0925a30335
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.c
@@ -0,0 +1,388 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem. The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/audit.h>
+
+#include "netlabel_addrlist.h"
+
+/*
+ * Address List Functions
+ */
+
+/**
+ * netlbl_af4list_search - Search for a matching IPv4 address entry
+ * @addr: IPv4 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head. If a matching address entry
+ * is found it is returned, otherwise NULL is returned. The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+ struct list_head *head)
+{
+ struct netlbl_af4list *iter;
+
+ list_for_each_entry_rcu(iter, head, list)
+ if (iter->valid && (addr & iter->mask) == iter->addr)
+ return iter;
+
+ return NULL;
+}
+
+/**
+ * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv4 address list given by @head. If an exact match if found
+ * it is returned, otherwise NULL is returned. The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+ __be32 mask,
+ struct list_head *head)
+{
+ struct netlbl_af4list *iter;
+
+ list_for_each_entry_rcu(iter, head, list)
+ if (iter->valid && iter->addr == addr && iter->mask == mask)
+ return iter;
+
+ return NULL;
+}
+
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_search - Search for a matching IPv6 address entry
+ * @addr: IPv6 address
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head. If a matching address entry
+ * is found it is returned, otherwise NULL is returned. The caller is
+ * responsible for calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+ struct list_head *head)
+{
+ struct netlbl_af6list *iter;
+
+ list_for_each_entry_rcu(iter, head, list)
+ if (iter->valid &&
+ ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
+ return iter;
+
+ return NULL;
+}
+
+/**
+ * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @head: the list head
+ *
+ * Description:
+ * Searches the IPv6 address list given by @head. If an exact match if found
+ * it is returned, otherwise NULL is returned. The caller is responsible for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+ const struct in6_addr *mask,
+ struct list_head *head)
+{
+ struct netlbl_af6list *iter;
+
+ list_for_each_entry_rcu(iter, head, list)
+ if (iter->valid &&
+ ipv6_addr_equal(&iter->addr, addr) &&
+ ipv6_addr_equal(&iter->mask, mask))
+ return iter;
+
+ return NULL;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_add - Add a new IPv4 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head. On success zero is
+ * returned, otherwise a negative value is returned. The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
+{
+ struct netlbl_af4list *iter;
+
+ iter = netlbl_af4list_search(entry->addr, head);
+ if (iter != NULL &&
+ iter->addr == entry->addr && iter->mask == entry->mask)
+ return -EEXIST;
+
+ /* in order to speed up address searches through the list (the common
+ * case) we need to keep the list in order based on the size of the
+ * address mask such that the entry with the widest mask (smallest
+ * numerical value) appears first in the list */
+ list_for_each_entry_rcu(iter, head, list)
+ if (iter->valid &&
+ ntohl(entry->mask) > ntohl(iter->mask)) {
+ __list_add_rcu(&entry->list,
+ iter->list.prev,
+ &iter->list);
+ return 0;
+ }
+ list_add_tail_rcu(&entry->list, head);
+ return 0;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_add - Add a new IPv6 address entry to a list
+ * @entry: address entry
+ * @head: the list head
+ *
+ * Description:
+ * Add a new address entry to the list pointed to by @head. On success zero is
+ * returned, otherwise a negative value is returned. The caller is responsible
+ * for calling the necessary locking functions.
+ *
+ */
+int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
+{
+ struct netlbl_af6list *iter;
+
+ iter = netlbl_af6list_search(&entry->addr, head);
+ if (iter != NULL &&
+ ipv6_addr_equal(&iter->addr, &entry->addr) &&
+ ipv6_addr_equal(&iter->mask, &entry->mask))
+ return -EEXIST;
+
+ /* in order to speed up address searches through the list (the common
+ * case) we need to keep the list in order based on the size of the
+ * address mask such that the entry with the widest mask (smallest
+ * numerical value) appears first in the list */
+ list_for_each_entry_rcu(iter, head, list)
+ if (iter->valid &&
+ ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
+ __list_add_rcu(&entry->list,
+ iter->list.prev,
+ &iter->list);
+ return 0;
+ }
+ list_add_tail_rcu(&entry->list, head);
+ return 0;
+}
+#endif /* IPv6 */
+
+/**
+ * netlbl_af4list_remove_entry - Remove an IPv4 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry. The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
+{
+ entry->valid = 0;
+ list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af4list_remove - Remove an IPv4 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head. Returns the
+ * entry on success, NULL on failure. The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+ struct list_head *head)
+{
+ struct netlbl_af4list *entry;
+
+ entry = netlbl_af4list_search(addr, head);
+ if (entry != NULL && entry->addr == addr && entry->mask == mask) {
+ netlbl_af4list_remove_entry(entry);
+ return entry;
+ }
+
+ return NULL;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_remove_entry - Remove an IPv6 address entry
+ * @entry: address entry
+ *
+ * Description:
+ * Remove the specified IP address entry. The caller is responsible for
+ * calling the necessary locking functions.
+ *
+ */
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
+{
+ entry->valid = 0;
+ list_del_rcu(&entry->list);
+}
+
+/**
+ * netlbl_af6list_remove - Remove an IPv6 address entry
+ * @addr: IP address
+ * @mask: IP address mask
+ * @head: the list head
+ *
+ * Description:
+ * Remove an IP address entry from the list pointed to by @head. Returns the
+ * entry on success, NULL on failure. The caller is responsible for calling
+ * the necessary locking functions.
+ *
+ */
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+ const struct in6_addr *mask,
+ struct list_head *head)
+{
+ struct netlbl_af6list *entry;
+
+ entry = netlbl_af6list_search(addr, head);
+ if (entry != NULL &&
+ ipv6_addr_equal(&entry->addr, addr) &&
+ ipv6_addr_equal(&entry->mask, mask)) {
+ netlbl_af6list_remove_entry(entry);
+ return entry;
+ }
+
+ return NULL;
+}
+#endif /* IPv6 */
+
+/*
+ * Audit Helper Functions
+ */
+
+/**
+ * netlbl_af4list_audit_addr - Audit an IPv4 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv4 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+ int src, const char *dev,
+ __be32 addr, __be32 mask)
+{
+ u32 mask_val = ntohl(mask);
+ char *dir = (src ? "src" : "dst");
+
+ if (dev != NULL)
+ audit_log_format(audit_buf, " netif=%s", dev);
+ audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
+ if (mask_val != 0xffffffff) {
+ u32 mask_len = 0;
+ while (mask_val > 0) {
+ mask_val <<= 1;
+ mask_len++;
+ }
+ audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+ }
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_af6list_audit_addr - Audit an IPv6 address
+ * @audit_buf: audit buffer
+ * @src: true if source address, false if destination
+ * @dev: network interface
+ * @addr: IP address
+ * @mask: IP address mask
+ *
+ * Description:
+ * Write the IPv6 address and address mask, if necessary, to @audit_buf.
+ *
+ */
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+ int src,
+ const char *dev,
+ const struct in6_addr *addr,
+ const struct in6_addr *mask)
+{
+ char *dir = (src ? "src" : "dst");
+
+ if (dev != NULL)
+ audit_log_format(audit_buf, " netif=%s", dev);
+ audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr));
+ if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
+ u32 mask_len = 0;
+ u32 mask_val;
+ int iter = -1;
+ while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
+ mask_len += 32;
+ mask_val = ntohl(mask->s6_addr32[iter]);
+ while (mask_val > 0) {
+ mask_val <<= 1;
+ mask_len++;
+ }
+ audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
+ }
+}
+#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h
new file mode 100644
index 00000000000..0242bead405
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.h
@@ -0,0 +1,189 @@
+/*
+ * NetLabel Network Address Lists
+ *
+ * This file contains network address list functions used to manage ordered
+ * lists of network addresses for use by the NetLabel subsystem. The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * 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 _NETLABEL_ADDRLIST_H
+#define _NETLABEL_ADDRLIST_H
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/in6.h>
+#include <linux/audit.h>
+
+/**
+ * struct netlbl_af4list - NetLabel IPv4 address list
+ * @addr: IPv4 address
+ * @mask: IPv4 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af4list {
+ __be32 addr;
+ __be32 mask;
+
+ u32 valid;
+ struct list_head list;
+};
+
+/**
+ * struct netlbl_af6list - NetLabel IPv6 address list
+ * @addr: IPv6 address
+ * @mask: IPv6 address mask
+ * @valid: valid flag
+ * @list: list structure, used internally
+ */
+struct netlbl_af6list {
+ struct in6_addr addr;
+ struct in6_addr mask;
+
+ u32 valid;
+ struct list_head list;
+};
+
+#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
+
+static inline struct netlbl_af4list *__af4list_valid(struct list_head *s,
+ struct list_head *h)
+{
+ struct list_head *i = s;
+ struct netlbl_af4list *n = __af4list_entry(s);
+ while (i != h && !n->valid) {
+ i = i->next;
+ n = __af4list_entry(i);
+ }
+ return n;
+}
+
+static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s,
+ struct list_head *h)
+{
+ struct list_head *i = s;
+ struct netlbl_af4list *n = __af4list_entry(s);
+ while (i != h && !n->valid) {
+ i = rcu_dereference(i->next);
+ n = __af4list_entry(i);
+ }
+ return n;
+}
+
+#define netlbl_af4list_foreach(iter, head) \
+ for (iter = __af4list_valid((head)->next, head); \
+ prefetch(iter->list.next), &iter->list != (head); \
+ iter = __af4list_valid(iter->list.next, head))
+
+#define netlbl_af4list_foreach_rcu(iter, head) \
+ for (iter = __af4list_valid_rcu((head)->next, head); \
+ prefetch(iter->list.next), &iter->list != (head); \
+ iter = __af4list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af4list_foreach_safe(iter, tmp, head) \
+ for (iter = __af4list_valid((head)->next, head), \
+ tmp = __af4list_valid(iter->list.next, head); \
+ &iter->list != (head); \
+ iter = tmp, tmp = __af4list_valid(iter->list.next, head))
+
+int netlbl_af4list_add(struct netlbl_af4list *entry,
+ struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
+ struct list_head *head);
+void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
+struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
+ struct list_head *head);
+struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
+ __be32 mask,
+ struct list_head *head);
+void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
+ int src, const char *dev,
+ __be32 addr, __be32 mask);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
+#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
+
+static inline struct netlbl_af6list *__af6list_valid(struct list_head *s,
+ struct list_head *h)
+{
+ struct list_head *i = s;
+ struct netlbl_af6list *n = __af6list_entry(s);
+ while (i != h && !n->valid) {
+ i = i->next;
+ n = __af6list_entry(i);
+ }
+ return n;
+}
+
+static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s,
+ struct list_head *h)
+{
+ struct list_head *i = s;
+ struct netlbl_af6list *n = __af6list_entry(s);
+ while (i != h && !n->valid) {
+ i = rcu_dereference(i->next);
+ n = __af6list_entry(i);
+ }
+ return n;
+}
+
+#define netlbl_af6list_foreach(iter, head) \
+ for (iter = __af6list_valid((head)->next, head); \
+ prefetch(iter->list.next), &iter->list != (head); \
+ iter = __af6list_valid(iter->list.next, head))
+
+#define netlbl_af6list_foreach_rcu(iter, head) \
+ for (iter = __af6list_valid_rcu((head)->next, head); \
+ prefetch(iter->list.next), &iter->list != (head); \
+ iter = __af6list_valid_rcu(iter->list.next, head))
+
+#define netlbl_af6list_foreach_safe(iter, tmp, head) \
+ for (iter = __af6list_valid((head)->next, head), \
+ tmp = __af6list_valid(iter->list.next, head); \
+ &iter->list != (head); \
+ iter = tmp, tmp = __af6list_valid(iter->list.next, head))
+
+int netlbl_af6list_add(struct netlbl_af6list *entry,
+ struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
+ const struct in6_addr *mask,
+ struct list_head *head);
+void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
+struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
+ struct list_head *head);
+struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
+ const struct in6_addr *mask,
+ struct list_head *head);
+void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
+ int src,
+ const char *dev,
+ const struct in6_addr *addr,
+ const struct in6_addr *mask);
+#endif /* IPV6 */
+
+#endif
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 0aec318bf0e..fff32b70efa 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -43,6 +43,7 @@
#include "netlabel_user.h"
#include "netlabel_cipso_v4.h"
#include "netlabel_mgmt.h"
+#include "netlabel_domainhash.h"
/* Argument struct for cipso_v4_doi_walk() */
struct netlbl_cipsov4_doiwalk_arg {
@@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg {
u32 seq;
};
+/* Argument struct for netlbl_domhsh_walk() */
+struct netlbl_domhsh_walk_arg {
+ struct netlbl_audit *audit_info;
+ u32 doi;
+};
+
/* NetLabel Generic NETLINK CIPSOv4 family */
static struct genl_family netlbl_cipsov4_gnl_family = {
.id = GENL_ID_GENERATE,
@@ -81,32 +88,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1
*/
/**
- * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
- * @entry: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that the memory allocated to the DOI definition can be released
- * safely.
- *
- */
-void netlbl_cipsov4_doi_free(struct rcu_head *entry)
-{
- struct cipso_v4_doi *ptr;
-
- ptr = container_of(entry, struct cipso_v4_doi, rcu);
- switch (ptr->type) {
- case CIPSO_V4_MAP_STD:
- kfree(ptr->map.std->lvl.cipso);
- kfree(ptr->map.std->lvl.local);
- kfree(ptr->map.std->cat.cipso);
- kfree(ptr->map.std->cat.local);
- break;
- }
- kfree(ptr);
-}
-
-/**
* netlbl_cipsov4_add_common - Parse the common sections of a ADD message
* @info: the Generic NETLINK info block
* @doi_def: the CIPSO V4 DOI definition
@@ -151,9 +132,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
* @info: the Generic NETLINK info block
*
* Description:
- * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
- * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
- * error.
+ * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine. Return zero on success and
+ * non-zero on error.
*
*/
static int netlbl_cipsov4_add_std(struct genl_info *info)
@@ -183,7 +164,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
ret_val = -ENOMEM;
goto add_std_failure;
}
- doi_def->type = CIPSO_V4_MAP_STD;
+ doi_def->type = CIPSO_V4_MAP_TRANS;
ret_val = netlbl_cipsov4_add_common(info, doi_def);
if (ret_val != 0)
@@ -342,7 +323,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
add_std_failure:
if (doi_def)
- netlbl_cipsov4_doi_free(&doi_def->rcu);
+ cipso_v4_doi_free(doi_def);
return ret_val;
}
@@ -379,7 +360,44 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
return 0;
add_pass_failure:
- netlbl_cipsov4_doi_free(&doi_def->rcu);
+ cipso_v4_doi_free(doi_def);
+ return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
+ * message and add it to the CIPSO V4 engine. Return zero on success and
+ * non-zero on error.
+ *
+ */
+static int netlbl_cipsov4_add_local(struct genl_info *info)
+{
+ int ret_val;
+ struct cipso_v4_doi *doi_def = NULL;
+
+ if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
+ return -EINVAL;
+
+ doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+ if (doi_def == NULL)
+ return -ENOMEM;
+ doi_def->type = CIPSO_V4_MAP_LOCAL;
+
+ ret_val = netlbl_cipsov4_add_common(info, doi_def);
+ if (ret_val != 0)
+ goto add_local_failure;
+
+ ret_val = cipso_v4_doi_add(doi_def);
+ if (ret_val != 0)
+ goto add_local_failure;
+ return 0;
+
+add_local_failure:
+ cipso_v4_doi_free(doi_def);
return ret_val;
}
@@ -412,14 +430,18 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
switch (type) {
- case CIPSO_V4_MAP_STD:
- type_str = "std";
+ case CIPSO_V4_MAP_TRANS:
+ type_str = "trans";
ret_val = netlbl_cipsov4_add_std(info);
break;
case CIPSO_V4_MAP_PASS:
type_str = "pass";
ret_val = netlbl_cipsov4_add_pass(info);
break;
+ case CIPSO_V4_MAP_LOCAL:
+ type_str = "local";
+ ret_val = netlbl_cipsov4_add_local(info);
+ break;
}
if (ret_val == 0)
atomic_inc(&netlabel_mgmt_protocount);
@@ -491,7 +513,7 @@ list_start:
doi_def = cipso_v4_doi_getdef(doi);
if (doi_def == NULL) {
ret_val = -EINVAL;
- goto list_failure;
+ goto list_failure_lock;
}
ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
@@ -516,7 +538,7 @@ list_start:
nla_nest_end(ans_skb, nla_a);
switch (doi_def->type) {
- case CIPSO_V4_MAP_STD:
+ case CIPSO_V4_MAP_TRANS:
nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
if (nla_a == NULL) {
ret_val = -ENOMEM;
@@ -655,7 +677,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct netlbl_cipsov4_doiwalk_arg cb_arg;
- int doi_skip = cb->args[0];
+ u32 doi_skip = cb->args[0];
cb_arg.nl_cb = cb;
cb_arg.skb = skb;
@@ -668,6 +690,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
}
/**
+ * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
+ * @entry: LSM domain mapping entry
+ * @arg: the netlbl_domhsh_walk_arg structure
+ *
+ * Description:
+ * This function is intended for use by netlbl_cipsov4_remove() as the callback
+ * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
+ * which are associated with the CIPSO DOI specified in @arg. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
+{
+ struct netlbl_domhsh_walk_arg *cb_arg = arg;
+
+ if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
+ entry->type_def.cipsov4->doi == cb_arg->doi)
+ return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
+
+ return 0;
+}
+
+/**
* netlbl_cipsov4_remove - Handle a REMOVE message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
@@ -681,8 +726,11 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
u32 doi = 0;
+ struct netlbl_domhsh_walk_arg cb_arg;
struct audit_buffer *audit_buf;
struct netlbl_audit audit_info;
+ u32 skip_bkt = 0;
+ u32 skip_chain = 0;
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
return -EINVAL;
@@ -690,11 +738,15 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
netlbl_netlink_auditinfo(skb, &audit_info);
- ret_val = cipso_v4_doi_remove(doi,
- &audit_info,
- netlbl_cipsov4_doi_free);
- if (ret_val == 0)
- atomic_dec(&netlabel_mgmt_protocount);
+ cb_arg.doi = doi;
+ cb_arg.audit_info = &audit_info;
+ ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
+ netlbl_cipsov4_remove_cb, &cb_arg);
+ if (ret_val == 0 || ret_val == -ENOENT) {
+ ret_val = cipso_v4_doi_remove(doi, &audit_info);
+ if (ret_val == 0)
+ atomic_dec(&netlabel_mgmt_protocount);
+ }
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
&audit_info);
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h
index 220cb9d06b4..c8a4079261f 100644
--- a/net/netlabel/netlabel_cipso_v4.h
+++ b/net/netlabel/netlabel_cipso_v4.h
@@ -45,12 +45,13 @@
* NLBL_CIPSOV4_A_MTYPE
* NLBL_CIPSOV4_A_TAGLST
*
- * If using CIPSO_V4_MAP_STD the following attributes are required:
+ * If using CIPSO_V4_MAP_TRANS the following attributes are required:
*
* NLBL_CIPSOV4_A_MLSLVLLST
* NLBL_CIPSOV4_A_MLSCATLST
*
- * If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ * are required.
*
* o REMOVE:
* Sent by an application to remove a specific DOI mapping table from the
@@ -76,12 +77,13 @@
* NLBL_CIPSOV4_A_MTYPE
* NLBL_CIPSOV4_A_TAGLST
*
- * If using CIPSO_V4_MAP_STD the following attributes are required:
+ * If using CIPSO_V4_MAP_TRANS the following attributes are required:
*
* NLBL_CIPSOV4_A_MLSLVLLST
* NLBL_CIPSOV4_A_MLSCATLST
*
- * If using CIPSO_V4_MAP_PASS no additional attributes are required.
+ * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
+ * are required.
*
* o LISTALL:
* This message is sent by an application to list the valid DOIs on the
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 643c032a3a5..5fadf10e5dd 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -11,7 +11,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* 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
@@ -40,6 +40,7 @@
#include <asm/bug.h>
#include "netlabel_mgmt.h"
+#include "netlabel_addrlist.h"
#include "netlabel_domainhash.h"
#include "netlabel_user.h"
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
static void netlbl_domhsh_free_entry(struct rcu_head *entry)
{
struct netlbl_dom_map *ptr;
+ struct netlbl_af4list *iter4;
+ struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct netlbl_af6list *iter6;
+ struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
ptr = container_of(entry, struct netlbl_dom_map, rcu);
+ if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
+ netlbl_af4list_foreach_safe(iter4, tmp4,
+ &ptr->type_def.addrsel->list4) {
+ netlbl_af4list_remove_entry(iter4);
+ kfree(netlbl_domhsh_addr4_entry(iter4));
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_safe(iter6, tmp6,
+ &ptr->type_def.addrsel->list6) {
+ netlbl_af6list_remove_entry(iter6);
+ kfree(netlbl_domhsh_addr6_entry(iter6));
+ }
+#endif /* IPv6 */
+ }
kfree(ptr->domain);
kfree(ptr);
}
@@ -115,13 +136,13 @@ static u32 netlbl_domhsh_hash(const char *key)
static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
{
u32 bkt;
+ struct list_head *bkt_list;
struct netlbl_dom_map *iter;
if (domain != NULL) {
bkt = netlbl_domhsh_hash(domain);
- list_for_each_entry_rcu(iter,
- &rcu_dereference(netlbl_domhsh)->tbl[bkt],
- list)
+ bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt];
+ list_for_each_entry_rcu(iter, bkt_list, list)
if (iter->valid && strcmp(iter->domain, domain) == 0)
return iter;
}
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
return entry;
}
+/**
+ * netlbl_domhsh_audit_add - Generate an audit entry for an add event
+ * @entry: the entry being added
+ * @addr4: the IPv4 address information
+ * @addr6: the IPv6 address information
+ * @result: the result code
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Generate an audit record for adding a new NetLabel/LSM mapping entry with
+ * the given information. Caller is responsibile for holding the necessary
+ * locks.
+ *
+ */
+static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
+ struct netlbl_af4list *addr4,
+ struct netlbl_af6list *addr6,
+ int result,
+ struct netlbl_audit *audit_info)
+{
+ struct audit_buffer *audit_buf;
+ struct cipso_v4_doi *cipsov4 = NULL;
+ u32 type;
+
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
+ if (audit_buf != NULL) {
+ audit_log_format(audit_buf, " nlbl_domain=%s",
+ entry->domain ? entry->domain : "(default)");
+ if (addr4 != NULL) {
+ struct netlbl_domaddr4_map *map4;
+ map4 = netlbl_domhsh_addr4_entry(addr4);
+ type = map4->type;
+ cipsov4 = map4->type_def.cipsov4;
+ netlbl_af4list_audit_addr(audit_buf, 0, NULL,
+ addr4->addr, addr4->mask);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ } else if (addr6 != NULL) {
+ struct netlbl_domaddr6_map *map6;
+ map6 = netlbl_domhsh_addr6_entry(addr6);
+ type = map6->type;
+ netlbl_af6list_audit_addr(audit_buf, 0, NULL,
+ &addr6->addr, &addr6->mask);
+#endif /* IPv6 */
+ } else {
+ type = entry->type;
+ cipsov4 = entry->type_def.cipsov4;
+ }
+ switch (type) {
+ case NETLBL_NLTYPE_UNLABELED:
+ audit_log_format(audit_buf, " nlbl_protocol=unlbl");
+ break;
+ case NETLBL_NLTYPE_CIPSOV4:
+ BUG_ON(cipsov4 == NULL);
+ audit_log_format(audit_buf,
+ " nlbl_protocol=cipsov4 cipso_doi=%u",
+ cipsov4->doi);
+ break;
+ }
+ audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
+ audit_log_end(audit_buf);
+ }
+}
+
/*
* Domain Hash Table Functions
*/
@@ -213,74 +297,106 @@ int __init netlbl_domhsh_init(u32 size)
int netlbl_domhsh_add(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info)
{
- int ret_val;
- u32 bkt;
- struct audit_buffer *audit_buf;
-
- switch (entry->type) {
- case NETLBL_NLTYPE_UNLABELED:
- ret_val = 0;
- break;
- case NETLBL_NLTYPE_CIPSOV4:
- ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
- entry->domain);
- break;
- default:
- return -EINVAL;
- }
- if (ret_val != 0)
- return ret_val;
-
- entry->valid = 1;
- INIT_RCU_HEAD(&entry->rcu);
+ int ret_val = 0;
+ struct netlbl_dom_map *entry_old;
+ struct netlbl_af4list *iter4;
+ struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct netlbl_af6list *iter6;
+ struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
rcu_read_lock();
+
spin_lock(&netlbl_domhsh_lock);
- if (entry->domain != NULL) {
- bkt = netlbl_domhsh_hash(entry->domain);
- if (netlbl_domhsh_search(entry->domain) == NULL)
+ if (entry->domain != NULL)
+ entry_old = netlbl_domhsh_search(entry->domain);
+ else
+ entry_old = netlbl_domhsh_search_def(entry->domain);
+ if (entry_old == NULL) {
+ entry->valid = 1;
+ INIT_RCU_HEAD(&entry->rcu);
+
+ if (entry->domain != NULL) {
+ u32 bkt = netlbl_domhsh_hash(entry->domain);
list_add_tail_rcu(&entry->list,
&rcu_dereference(netlbl_domhsh)->tbl[bkt]);
- else
- ret_val = -EEXIST;
- } else {
- INIT_LIST_HEAD(&entry->list);
- if (rcu_dereference(netlbl_domhsh_def) == NULL)
+ } else {
+ INIT_LIST_HEAD(&entry->list);
rcu_assign_pointer(netlbl_domhsh_def, entry);
- else
- ret_val = -EEXIST;
- }
- spin_unlock(&netlbl_domhsh_lock);
- audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
- if (audit_buf != NULL) {
- audit_log_format(audit_buf,
- " nlbl_domain=%s",
- entry->domain ? entry->domain : "(default)");
- switch (entry->type) {
- case NETLBL_NLTYPE_UNLABELED:
- audit_log_format(audit_buf, " nlbl_protocol=unlbl");
- break;
- case NETLBL_NLTYPE_CIPSOV4:
- audit_log_format(audit_buf,
- " nlbl_protocol=cipsov4 cipso_doi=%u",
- entry->type_def.cipsov4->doi);
- break;
}
- audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
- audit_log_end(audit_buf);
- }
- rcu_read_unlock();
- if (ret_val != 0) {
- switch (entry->type) {
- case NETLBL_NLTYPE_CIPSOV4:
- if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
- entry->domain) != 0)
- BUG();
- break;
+ if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+ netlbl_af4list_foreach_rcu(iter4,
+ &entry->type_def.addrsel->list4)
+ netlbl_domhsh_audit_add(entry, iter4, NULL,
+ ret_val, audit_info);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_rcu(iter6,
+ &entry->type_def.addrsel->list6)
+ netlbl_domhsh_audit_add(entry, NULL, iter6,
+ ret_val, audit_info);
+#endif /* IPv6 */
+ } else
+ netlbl_domhsh_audit_add(entry, NULL, NULL,
+ ret_val, audit_info);
+ } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
+ entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+ struct list_head *old_list4;
+ struct list_head *old_list6;
+
+ old_list4 = &entry_old->type_def.addrsel->list4;
+ old_list6 = &entry_old->type_def.addrsel->list6;
+
+ /* we only allow the addition of address selectors if all of
+ * the selectors do not exist in the existing domain map */
+ netlbl_af4list_foreach_rcu(iter4,
+ &entry->type_def.addrsel->list4)
+ if (netlbl_af4list_search_exact(iter4->addr,
+ iter4->mask,
+ old_list4)) {
+ ret_val = -EEXIST;
+ goto add_return;
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_rcu(iter6,
+ &entry->type_def.addrsel->list6)
+ if (netlbl_af6list_search_exact(&iter6->addr,
+ &iter6->mask,
+ old_list6)) {
+ ret_val = -EEXIST;
+ goto add_return;
+ }
+#endif /* IPv6 */
+
+ netlbl_af4list_foreach_safe(iter4, tmp4,
+ &entry->type_def.addrsel->list4) {
+ netlbl_af4list_remove_entry(iter4);
+ iter4->valid = 1;
+ ret_val = netlbl_af4list_add(iter4, old_list4);
+ netlbl_domhsh_audit_add(entry_old, iter4, NULL,
+ ret_val, audit_info);
+ if (ret_val != 0)
+ goto add_return;
}
- }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_safe(iter6, tmp6,
+ &entry->type_def.addrsel->list6) {
+ netlbl_af6list_remove_entry(iter6);
+ iter6->valid = 1;
+ ret_val = netlbl_af6list_add(iter6, old_list6);
+ netlbl_domhsh_audit_add(entry_old, NULL, iter6,
+ ret_val, audit_info);
+ if (ret_val != 0)
+ goto add_return;
+ }
+#endif /* IPv6 */
+ } else
+ ret_val = -EINVAL;
+add_return:
+ spin_unlock(&netlbl_domhsh_lock);
+ rcu_read_unlock();
return ret_val;
}
@@ -302,35 +418,26 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
}
/**
- * netlbl_domhsh_remove - Removes an entry from the domain hash table
- * @domain: the domain to remove
+ * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
+ * @entry: the entry to remove
* @audit_info: NetLabel audit information
*
* Description:
* Removes an entry from the domain hash table and handles any updates to the
- * lower level protocol handler (i.e. CIPSO). Returns zero on success,
- * negative on failure.
+ * lower level protocol handler (i.e. CIPSO). Caller is responsible for
+ * ensuring that the RCU read lock is held. Returns zero on success, negative
+ * on failure.
*
*/
-int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+ struct netlbl_audit *audit_info)
{
- int ret_val = -ENOENT;
- struct netlbl_dom_map *entry;
+ int ret_val = 0;
struct audit_buffer *audit_buf;
- rcu_read_lock();
- if (domain)
- entry = netlbl_domhsh_search(domain);
- else
- entry = netlbl_domhsh_search_def(domain);
if (entry == NULL)
- goto remove_return;
- switch (entry->type) {
- case NETLBL_NLTYPE_CIPSOV4:
- cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
- entry->domain);
- break;
- }
+ return -ENOENT;
+
spin_lock(&netlbl_domhsh_lock);
if (entry->valid) {
entry->valid = 0;
@@ -338,8 +445,8 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
list_del_rcu(&entry->list);
else
rcu_assign_pointer(netlbl_domhsh_def, NULL);
- ret_val = 0;
- }
+ } else
+ ret_val = -ENOENT;
spin_unlock(&netlbl_domhsh_lock);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
@@ -351,10 +458,54 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
audit_log_end(audit_buf);
}
-remove_return:
- rcu_read_unlock();
- if (ret_val == 0)
+ if (ret_val == 0) {
+ struct netlbl_af4list *iter4;
+ struct netlbl_domaddr4_map *map4;
+
+ switch (entry->type) {
+ case NETLBL_NLTYPE_ADDRSELECT:
+ netlbl_af4list_foreach_rcu(iter4,
+ &entry->type_def.addrsel->list4) {
+ map4 = netlbl_domhsh_addr4_entry(iter4);
+ cipso_v4_doi_putdef(map4->type_def.cipsov4);
+ }
+ /* no need to check the IPv6 list since we currently
+ * support only unlabeled protocols for IPv6 */
+ break;
+ case NETLBL_NLTYPE_CIPSOV4:
+ cipso_v4_doi_putdef(entry->type_def.cipsov4);
+ break;
+ }
call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+ }
+
+ return ret_val;
+}
+
+/**
+ * netlbl_domhsh_remove - Removes an entry from the domain hash table
+ * @domain: the domain to remove
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an entry from the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO). Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
+{
+ int ret_val;
+ struct netlbl_dom_map *entry;
+
+ rcu_read_lock();
+ if (domain)
+ entry = netlbl_domhsh_search(domain);
+ else
+ entry = netlbl_domhsh_search_def(domain);
+ ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
+ rcu_read_unlock();
+
return ret_val;
}
@@ -389,6 +540,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
}
/**
+ * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL. The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+ __be32 addr)
+{
+ struct netlbl_dom_map *dom_iter;
+ struct netlbl_af4list *addr_iter;
+
+ dom_iter = netlbl_domhsh_search_def(domain);
+ if (dom_iter == NULL)
+ return NULL;
+ if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+ return NULL;
+
+ addr_iter = netlbl_af4list_search(addr,
+ &dom_iter->type_def.addrsel->list4);
+ if (addr_iter == NULL)
+ return NULL;
+
+ return netlbl_domhsh_addr4_entry(addr_iter);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/**
+ * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ * @addr: the IP address to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain
+ * and @addr, return a pointer to a copy of the entry or NULL. The caller is
+ * responsible for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+ const struct in6_addr *addr)
+{
+ struct netlbl_dom_map *dom_iter;
+ struct netlbl_af6list *addr_iter;
+
+ dom_iter = netlbl_domhsh_search_def(domain);
+ if (dom_iter == NULL)
+ return NULL;
+ if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
+ return NULL;
+
+ addr_iter = netlbl_af6list_search(addr,
+ &dom_iter->type_def.addrsel->list6);
+ if (addr_iter == NULL)
+ return NULL;
+
+ return netlbl_domhsh_addr6_entry(addr_iter);
+}
+#endif /* IPv6 */
+
+/**
* netlbl_domhsh_walk - Iterate through the domain mapping hash table
* @skip_bkt: the number of buckets to skip at the start
* @skip_chain: the number of entries to skip in the first iterated bucket
@@ -410,6 +625,7 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
{
int ret_val = -ENOENT;
u32 iter_bkt;
+ struct list_head *iter_list;
struct netlbl_dom_map *iter_entry;
u32 chain_cnt = 0;
@@ -417,9 +633,8 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
for (iter_bkt = *skip_bkt;
iter_bkt < rcu_dereference(netlbl_domhsh)->size;
iter_bkt++, chain_cnt = 0) {
- list_for_each_entry_rcu(iter_entry,
- &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt],
- list)
+ iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
+ list_for_each_entry_rcu(iter_entry, iter_list, list)
if (iter_entry->valid) {
if (chain_cnt++ < *skip_chain)
continue;
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index 8220990ceb9..bfcb6763a1a 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -11,7 +11,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* 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
@@ -36,16 +36,43 @@
#include <linux/rcupdate.h>
#include <linux/list.h>
+#include "netlabel_addrlist.h"
+
/* Domain hash table size */
/* XXX - currently this number is an uneducated guess */
#define NETLBL_DOMHSH_BITSIZE 7
-/* Domain mapping definition struct */
+/* Domain mapping definition structures */
+#define netlbl_domhsh_addr4_entry(iter) \
+ container_of(iter, struct netlbl_domaddr4_map, list)
+struct netlbl_domaddr4_map {
+ u32 type;
+ union {
+ struct cipso_v4_doi *cipsov4;
+ } type_def;
+
+ struct netlbl_af4list list;
+};
+#define netlbl_domhsh_addr6_entry(iter) \
+ container_of(iter, struct netlbl_domaddr6_map, list)
+struct netlbl_domaddr6_map {
+ u32 type;
+
+ /* NOTE: no 'type_def' union needed at present since we don't currently
+ * support any IPv6 labeling protocols */
+
+ struct netlbl_af6list list;
+};
+struct netlbl_domaddr_map {
+ struct list_head list4;
+ struct list_head list6;
+};
struct netlbl_dom_map {
char *domain;
u32 type;
union {
struct cipso_v4_doi *cipsov4;
+ struct netlbl_domaddr_map *addrsel;
} type_def;
u32 valid;
@@ -61,12 +88,21 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info);
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
+ struct netlbl_audit *audit_info);
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
+struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
+ __be32 addr);
int netlbl_domhsh_walk(u32 *skip_bkt,
u32 *skip_chain,
int (*callback) (struct netlbl_dom_map *entry, void *arg),
void *cb_arg);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+ const struct in6_addr *addr);
+#endif /* IPv6 */
+
#endif
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 39793a1a93a..b32eceb3ab0 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -10,7 +10,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* 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
@@ -82,7 +82,7 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (entry == NULL)
- goto cfg_unlbl_add_map_failure;
+ return -ENOMEM;
if (domain != NULL) {
entry->domain = kstrdup(domain, GFP_ATOMIC);
if (entry->domain == NULL)
@@ -104,49 +104,6 @@ cfg_unlbl_add_map_failure:
}
/**
- * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
- * @doi_def: the DOI definition
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Add a new CIPSOv4 DOI definition to the NetLabel subsystem. Returns zero on
- * success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
- struct netlbl_audit *audit_info)
-{
- int ret_val;
- const char *type_str;
- struct audit_buffer *audit_buf;
-
- ret_val = cipso_v4_doi_add(doi_def);
-
- audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
- audit_info);
- if (audit_buf != NULL) {
- switch (doi_def->type) {
- case CIPSO_V4_MAP_STD:
- type_str = "std";
- break;
- case CIPSO_V4_MAP_PASS:
- type_str = "pass";
- break;
- default:
- type_str = "(unknown)";
- }
- audit_log_format(audit_buf,
- " cipso_doi=%u cipso_type=%s res=%u",
- doi_def->doi,
- type_str,
- ret_val == 0 ? 1 : 0);
- audit_log_end(audit_buf);
- }
-
- return ret_val;
-}
-
-/**
* netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
* @doi_def: the DOI definition
* @domain: the domain mapping to add
@@ -164,58 +121,71 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
struct netlbl_audit *audit_info)
{
int ret_val = -ENOMEM;
+ u32 doi;
+ u32 doi_type;
struct netlbl_dom_map *entry;
+ const char *type_str;
+ struct audit_buffer *audit_buf;
+
+ doi = doi_def->doi;
+ doi_type = doi_def->type;
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (entry == NULL)
- goto cfg_cipsov4_add_map_failure;
+ return -ENOMEM;
if (domain != NULL) {
entry->domain = kstrdup(domain, GFP_ATOMIC);
if (entry->domain == NULL)
goto cfg_cipsov4_add_map_failure;
}
- entry->type = NETLBL_NLTYPE_CIPSOV4;
- entry->type_def.cipsov4 = doi_def;
-
- /* Grab a RCU read lock here so nothing happens to the doi_def variable
- * between adding it to the CIPSOv4 protocol engine and adding a
- * domain mapping for it. */
- rcu_read_lock();
- ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info);
+ ret_val = cipso_v4_doi_add(doi_def);
if (ret_val != 0)
- goto cfg_cipsov4_add_map_failure_unlock;
+ goto cfg_cipsov4_add_map_failure_remove_doi;
+ entry->type = NETLBL_NLTYPE_CIPSOV4;
+ entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi);
+ if (entry->type_def.cipsov4 == NULL) {
+ ret_val = -ENOENT;
+ goto cfg_cipsov4_add_map_failure_remove_doi;
+ }
ret_val = netlbl_domhsh_add(entry, audit_info);
if (ret_val != 0)
- goto cfg_cipsov4_add_map_failure_remove_doi;
- rcu_read_unlock();
+ goto cfg_cipsov4_add_map_failure_release_doi;
- return 0;
+cfg_cipsov4_add_map_return:
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
+ audit_info);
+ if (audit_buf != NULL) {
+ switch (doi_type) {
+ case CIPSO_V4_MAP_TRANS:
+ type_str = "trans";
+ break;
+ case CIPSO_V4_MAP_PASS:
+ type_str = "pass";
+ break;
+ case CIPSO_V4_MAP_LOCAL:
+ type_str = "local";
+ break;
+ default:
+ type_str = "(unknown)";
+ }
+ audit_log_format(audit_buf,
+ " cipso_doi=%u cipso_type=%s res=%u",
+ doi, type_str, ret_val == 0 ? 1 : 0);
+ audit_log_end(audit_buf);
+ }
+ return ret_val;
+
+cfg_cipsov4_add_map_failure_release_doi:
+ cipso_v4_doi_putdef(doi_def);
cfg_cipsov4_add_map_failure_remove_doi:
- cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free);
-cfg_cipsov4_add_map_failure_unlock:
- rcu_read_unlock();
+ cipso_v4_doi_remove(doi, audit_info);
cfg_cipsov4_add_map_failure:
if (entry != NULL)
kfree(entry->domain);
kfree(entry);
- return ret_val;
-}
-
-/**
- * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
- * @doi: the CIPSO DOI value
- * @audit_info: NetLabel audit information
- *
- * Description:
- * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
- * Returns zero on success, negative values on failure.
- *
- */
-int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
-{
- return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free);
+ goto cfg_cipsov4_add_map_return;
}
/*
@@ -452,7 +422,9 @@ int netlbl_enabled(void)
* Attach the correct label to the given socket using the security attributes
* specified in @secattr. This function requires exclusive access to @sk,
* which means it either needs to be in the process of being created or locked.
- * Returns zero on success, negative values on failure.
+ * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
+ * network address selectors (can't blindly label the socket), and negative
+ * values on all other failures.
*
*/
int netlbl_sock_setattr(struct sock *sk,
@@ -466,6 +438,9 @@ int netlbl_sock_setattr(struct sock *sk,
if (dom_entry == NULL)
goto socket_setattr_return;
switch (dom_entry->type) {
+ case NETLBL_NLTYPE_ADDRSELECT:
+ ret_val = -EDESTADDRREQ;
+ break;
case NETLBL_NLTYPE_CIPSOV4:
ret_val = cipso_v4_sock_setattr(sk,
dom_entry->type_def.cipsov4,
@@ -484,6 +459,20 @@ socket_setattr_return:
}
/**
+ * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
+ * @sk: the socket
+ *
+ * Description:
+ * Remove all the NetLabel labeling from @sk. The caller is responsible for
+ * ensuring that @sk is locked.
+ *
+ */
+void netlbl_sock_delattr(struct sock *sk)
+{
+ cipso_v4_sock_delattr(sk);
+}
+
+/**
* netlbl_sock_getattr - Determine the security attributes of a sock
* @sk: the sock
* @secattr: the security attributes
@@ -501,6 +490,128 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
}
/**
+ * netlbl_conn_setattr - Label a connected socket using the correct protocol
+ * @sk: the socket to label
+ * @addr: the destination address
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given connected socket using the security
+ * attributes specified in @secattr. The caller is responsible for ensuring
+ * that @sk is locked. Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_conn_setattr(struct sock *sk,
+ struct sockaddr *addr,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val;
+ struct sockaddr_in *addr4;
+ struct netlbl_domaddr4_map *af4_entry;
+
+ rcu_read_lock();
+ switch (addr->sa_family) {
+ case AF_INET:
+ addr4 = (struct sockaddr_in *)addr;
+ af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+ addr4->sin_addr.s_addr);
+ if (af4_entry == NULL) {
+ ret_val = -ENOENT;
+ goto conn_setattr_return;
+ }
+ switch (af4_entry->type) {
+ case NETLBL_NLTYPE_CIPSOV4:
+ ret_val = cipso_v4_sock_setattr(sk,
+ af4_entry->type_def.cipsov4,
+ secattr);
+ break;
+ case NETLBL_NLTYPE_UNLABELED:
+ /* just delete the protocols we support for right now
+ * but we could remove other protocols if needed */
+ cipso_v4_sock_delattr(sk);
+ ret_val = 0;
+ break;
+ default:
+ ret_val = -ENOENT;
+ }
+ break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ /* since we don't support any IPv6 labeling protocols right
+ * now we can optimize everything away until we do */
+ ret_val = 0;
+ break;
+#endif /* IPv6 */
+ default:
+ ret_val = 0;
+ }
+
+conn_setattr_return:
+ rcu_read_unlock();
+ return ret_val;
+}
+
+/**
+ * netlbl_skbuff_setattr - Label a packet using the correct protocol
+ * @skb: the packet
+ * @family: protocol family
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given packet using the security attributes
+ * specified in @secattr. Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_skbuff_setattr(struct sk_buff *skb,
+ u16 family,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val;
+ struct iphdr *hdr4;
+ struct netlbl_domaddr4_map *af4_entry;
+
+ rcu_read_lock();
+ switch (family) {
+ case AF_INET:
+ hdr4 = ip_hdr(skb);
+ af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
+ hdr4->daddr);
+ if (af4_entry == NULL) {
+ ret_val = -ENOENT;
+ goto skbuff_setattr_return;
+ }
+ switch (af4_entry->type) {
+ case NETLBL_NLTYPE_CIPSOV4:
+ ret_val = cipso_v4_skbuff_setattr(skb,
+ af4_entry->type_def.cipsov4,
+ secattr);
+ break;
+ case NETLBL_NLTYPE_UNLABELED:
+ /* just delete the protocols we support for right now
+ * but we could remove other protocols if needed */
+ ret_val = cipso_v4_skbuff_delattr(skb);
+ break;
+ default:
+ ret_val = -ENOENT;
+ }
+ break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ /* since we don't support any IPv6 labeling protocols right
+ * now we can optimize everything away until we do */
+ ret_val = 0;
+ break;
+#endif /* IPv6 */
+ default:
+ ret_val = 0;
+ }
+
+skbuff_setattr_return:
+ rcu_read_unlock();
+ return ret_val;
+}
+
+/**
* netlbl_skbuff_getattr - Determine the security attributes of a packet
* @skb: the packet
* @family: protocol family
@@ -528,6 +639,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
* netlbl_skbuff_err - Handle a LSM error on a sk_buff
* @skb: the packet
* @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
*
* Description:
* Deal with a LSM problem when handling the packet in @skb, typically this is
@@ -535,10 +647,10 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
* according to the packet's labeling protocol.
*
*/
-void netlbl_skbuff_err(struct sk_buff *skb, int error)
+void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
{
if (CIPSO_V4_OPTEXIST(skb))
- cipso_v4_error(skb, error, 0);
+ cipso_v4_error(skb, error, gateway);
}
/**
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 44be5d5261f..ee769ecaa13 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -10,7 +10,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* 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
@@ -32,9 +32,13 @@
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/in6.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <net/genetlink.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <asm/atomic.h>
@@ -71,86 +75,337 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
};
/*
- * NetLabel Command Handlers
+ * Helper Functions
*/
/**
* netlbl_mgmt_add - Handle an ADD message
- * @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
+ * @audit_info: NetLabel audit information
*
* Description:
- * Process a user generated ADD message and add the domains from the message
- * to the hash table. See netlabel.h for a description of the message format.
- * Returns zero on success, negative values on failure.
+ * Helper function for the ADD and ADDDEF messages to add the domain mappings
+ * from the message to the hash table. See netlabel.h for a description of the
+ * message format. Returns zero on success, negative values on failure.
*
*/
-static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
+static int netlbl_mgmt_add_common(struct genl_info *info,
+ struct netlbl_audit *audit_info)
{
int ret_val = -EINVAL;
struct netlbl_dom_map *entry = NULL;
- size_t tmp_size;
+ struct netlbl_domaddr_map *addrmap = NULL;
+ struct cipso_v4_doi *cipsov4 = NULL;
u32 tmp_val;
- struct netlbl_audit audit_info;
-
- if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
- !info->attrs[NLBL_MGMT_A_PROTOCOL])
- goto add_failure;
-
- netlbl_netlink_auditinfo(skb, &audit_info);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL) {
ret_val = -ENOMEM;
goto add_failure;
}
- tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
- entry->domain = kmalloc(tmp_size, GFP_KERNEL);
- if (entry->domain == NULL) {
- ret_val = -ENOMEM;
- goto add_failure;
- }
entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
- nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
+ if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
+ size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
+ entry->domain = kmalloc(tmp_size, GFP_KERNEL);
+ if (entry->domain == NULL) {
+ ret_val = -ENOMEM;
+ goto add_failure;
+ }
+ nla_strlcpy(entry->domain,
+ info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
+ }
+
+ /* NOTE: internally we allow/use a entry->type value of
+ * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
+ * to pass that as a protocol value because we need to know the
+ * "real" protocol */
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
- ret_val = netlbl_domhsh_add(entry, &audit_info);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
goto add_failure;
tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
- /* We should be holding a rcu_read_lock() here while we hold
- * the result but since the entry will always be deleted when
- * the CIPSO DOI is deleted we aren't going to keep the
- * lock. */
- rcu_read_lock();
- entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
- if (entry->type_def.cipsov4 == NULL) {
- rcu_read_unlock();
+ cipsov4 = cipso_v4_doi_getdef(tmp_val);
+ if (cipsov4 == NULL)
goto add_failure;
- }
- ret_val = netlbl_domhsh_add(entry, &audit_info);
- rcu_read_unlock();
+ entry->type_def.cipsov4 = cipsov4;
break;
default:
goto add_failure;
}
+
+ if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
+ struct in_addr *addr;
+ struct in_addr *mask;
+ struct netlbl_domaddr4_map *map;
+
+ addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+ if (addrmap == NULL) {
+ ret_val = -ENOMEM;
+ goto add_failure;
+ }
+ INIT_LIST_HEAD(&addrmap->list4);
+ INIT_LIST_HEAD(&addrmap->list6);
+
+ if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
+ sizeof(struct in_addr)) {
+ ret_val = -EINVAL;
+ goto add_failure;
+ }
+ if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
+ sizeof(struct in_addr)) {
+ ret_val = -EINVAL;
+ goto add_failure;
+ }
+ addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
+ mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (map == NULL) {
+ ret_val = -ENOMEM;
+ goto add_failure;
+ }
+ map->list.addr = addr->s_addr & mask->s_addr;
+ map->list.mask = mask->s_addr;
+ map->list.valid = 1;
+ map->type = entry->type;
+ if (cipsov4)
+ map->type_def.cipsov4 = cipsov4;
+
+ ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
+ if (ret_val != 0) {
+ kfree(map);
+ goto add_failure;
+ }
+
+ entry->type = NETLBL_NLTYPE_ADDRSELECT;
+ entry->type_def.addrsel = addrmap;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
+ struct in6_addr *addr;
+ struct in6_addr *mask;
+ struct netlbl_domaddr6_map *map;
+
+ addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
+ if (addrmap == NULL) {
+ ret_val = -ENOMEM;
+ goto add_failure;
+ }
+ INIT_LIST_HEAD(&addrmap->list4);
+ INIT_LIST_HEAD(&addrmap->list6);
+
+ if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
+ sizeof(struct in6_addr)) {
+ ret_val = -EINVAL;
+ goto add_failure;
+ }
+ if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
+ sizeof(struct in6_addr)) {
+ ret_val = -EINVAL;
+ goto add_failure;
+ }
+ addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
+ mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (map == NULL) {
+ ret_val = -ENOMEM;
+ goto add_failure;
+ }
+ ipv6_addr_copy(&map->list.addr, addr);
+ map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+ map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+ map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+ map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+ ipv6_addr_copy(&map->list.mask, mask);
+ map->list.valid = 1;
+ map->type = entry->type;
+
+ ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
+ if (ret_val != 0) {
+ kfree(map);
+ goto add_failure;
+ }
+
+ entry->type = NETLBL_NLTYPE_ADDRSELECT;
+ entry->type_def.addrsel = addrmap;
+#endif /* IPv6 */
+ }
+
+ ret_val = netlbl_domhsh_add(entry, audit_info);
if (ret_val != 0)
goto add_failure;
return 0;
add_failure:
+ if (cipsov4)
+ cipso_v4_doi_putdef(cipsov4);
if (entry)
kfree(entry->domain);
+ kfree(addrmap);
kfree(entry);
return ret_val;
}
/**
+ * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
+ * @skb: the NETLINK buffer
+ * @entry: the map entry
+ *
+ * Description:
+ * This function is a helper function used by the LISTALL and LISTDEF command
+ * handlers. The caller is responsibile for ensuring that the RCU read lock
+ * is held. Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_listentry(struct sk_buff *skb,
+ struct netlbl_dom_map *entry)
+{
+ int ret_val;
+ struct nlattr *nla_a;
+ struct nlattr *nla_b;
+ struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct netlbl_af6list *iter6;
+#endif
+
+ if (entry->domain != NULL) {
+ ret_val = nla_put_string(skb,
+ NLBL_MGMT_A_DOMAIN, entry->domain);
+ if (ret_val != 0)
+ return ret_val;
+ }
+
+ switch (entry->type) {
+ case NETLBL_NLTYPE_ADDRSELECT:
+ nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
+ if (nla_a == NULL)
+ return -ENOMEM;
+
+ netlbl_af4list_foreach_rcu(iter4,
+ &entry->type_def.addrsel->list4) {
+ struct netlbl_domaddr4_map *map4;
+ struct in_addr addr_struct;
+
+ nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+ if (nla_b == NULL)
+ return -ENOMEM;
+
+ addr_struct.s_addr = iter4->addr;
+ ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
+ sizeof(struct in_addr),
+ &addr_struct);
+ if (ret_val != 0)
+ return ret_val;
+ addr_struct.s_addr = iter4->mask;
+ ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
+ sizeof(struct in_addr),
+ &addr_struct);
+ if (ret_val != 0)
+ return ret_val;
+ map4 = netlbl_domhsh_addr4_entry(iter4);
+ ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+ map4->type);
+ if (ret_val != 0)
+ return ret_val;
+ switch (map4->type) {
+ case NETLBL_NLTYPE_CIPSOV4:
+ ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+ map4->type_def.cipsov4->doi);
+ if (ret_val != 0)
+ return ret_val;
+ break;
+ }
+
+ nla_nest_end(skb, nla_b);
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_rcu(iter6,
+ &entry->type_def.addrsel->list6) {
+ struct netlbl_domaddr6_map *map6;
+
+ nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
+ if (nla_b == NULL)
+ return -ENOMEM;
+
+ ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
+ sizeof(struct in6_addr),
+ &iter6->addr);
+ if (ret_val != 0)
+ return ret_val;
+ ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
+ sizeof(struct in6_addr),
+ &iter6->mask);
+ if (ret_val != 0)
+ return ret_val;
+ map6 = netlbl_domhsh_addr6_entry(iter6);
+ ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
+ map6->type);
+ if (ret_val != 0)
+ return ret_val;
+
+ nla_nest_end(skb, nla_b);
+ }
+#endif /* IPv6 */
+
+ nla_nest_end(skb, nla_a);
+ break;
+ case NETLBL_NLTYPE_UNLABELED:
+ ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+ break;
+ case NETLBL_NLTYPE_CIPSOV4:
+ ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+ if (ret_val != 0)
+ return ret_val;
+ ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
+ entry->type_def.cipsov4->doi);
+ break;
+ }
+
+ return ret_val;
+}
+
+/*
+ * NetLabel Command Handlers
+ */
+
+/**
+ * netlbl_mgmt_add - Handle an ADD message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Process a user generated ADD message and add the domains from the message
+ * to the hash table. See netlabel.h for a description of the message format.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
+{
+ struct netlbl_audit audit_info;
+
+ if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
+ (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+ (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+ info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+ (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+ info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+ ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+ (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+ ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+ (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+ return -EINVAL;
+
+ netlbl_netlink_auditinfo(skb, &audit_info);
+
+ return netlbl_mgmt_add_common(info, &audit_info);
+}
+
+/**
* netlbl_mgmt_remove - Handle a REMOVE message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
@@ -198,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
if (data == NULL)
goto listall_cb_failure;
- ret_val = nla_put_string(cb_arg->skb,
- NLBL_MGMT_A_DOMAIN,
- entry->domain);
+ ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
if (ret_val != 0)
goto listall_cb_failure;
- ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
- if (ret_val != 0)
- goto listall_cb_failure;
- switch (entry->type) {
- case NETLBL_NLTYPE_CIPSOV4:
- ret_val = nla_put_u32(cb_arg->skb,
- NLBL_MGMT_A_CV4DOI,
- entry->type_def.cipsov4->doi);
- if (ret_val != 0)
- goto listall_cb_failure;
- break;
- }
cb_arg->seq++;
return genlmsg_end(cb_arg->skb, data);
@@ -268,56 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb,
*/
static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
{
- int ret_val = -EINVAL;
- struct netlbl_dom_map *entry = NULL;
- u32 tmp_val;
struct netlbl_audit audit_info;
- if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
- goto adddef_failure;
+ if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
+ (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
+ info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
+ (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
+ info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
+ ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
+ (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
+ ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
+ (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
+ return -EINVAL;
netlbl_netlink_auditinfo(skb, &audit_info);
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (entry == NULL) {
- ret_val = -ENOMEM;
- goto adddef_failure;
- }
- entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
-
- switch (entry->type) {
- case NETLBL_NLTYPE_UNLABELED:
- ret_val = netlbl_domhsh_add_default(entry, &audit_info);
- break;
- case NETLBL_NLTYPE_CIPSOV4:
- if (!info->attrs[NLBL_MGMT_A_CV4DOI])
- goto adddef_failure;
-
- tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
- /* We should be holding a rcu_read_lock() here while we hold
- * the result but since the entry will always be deleted when
- * the CIPSO DOI is deleted we aren't going to keep the
- * lock. */
- rcu_read_lock();
- entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
- if (entry->type_def.cipsov4 == NULL) {
- rcu_read_unlock();
- goto adddef_failure;
- }
- ret_val = netlbl_domhsh_add_default(entry, &audit_info);
- rcu_read_unlock();
- break;
- default:
- goto adddef_failure;
- }
- if (ret_val != 0)
- goto adddef_failure;
-
- return 0;
-
-adddef_failure:
- kfree(entry);
- return ret_val;
+ return netlbl_mgmt_add_common(info, &audit_info);
}
/**
@@ -371,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
ret_val = -ENOENT;
goto listdef_failure_lock;
}
- ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
- if (ret_val != 0)
- goto listdef_failure_lock;
- switch (entry->type) {
- case NETLBL_NLTYPE_CIPSOV4:
- ret_val = nla_put_u32(ans_skb,
- NLBL_MGMT_A_CV4DOI,
- entry->type_def.cipsov4->doi);
- if (ret_val != 0)
- goto listdef_failure_lock;
- break;
- }
+ ret_val = netlbl_mgmt_listentry(ans_skb, entry);
rcu_read_unlock();
+ if (ret_val != 0)
+ goto listdef_failure;
genlmsg_end(ans_skb, data);
return genlmsg_reply(ans_skb, info);
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
index a43bff169d6..05d96431f81 100644
--- a/net/netlabel/netlabel_mgmt.h
+++ b/net/netlabel/netlabel_mgmt.h
@@ -45,6 +45,16 @@
* NLBL_MGMT_A_DOMAIN
* NLBL_MGMT_A_PROTOCOL
*
+ * If IPv4 is specified the following attributes are required:
+ *
+ * NLBL_MGMT_A_IPV4ADDR
+ * NLBL_MGMT_A_IPV4MASK
+ *
+ * If IPv6 is specified the following attributes are required:
+ *
+ * NLBL_MGMT_A_IPV6ADDR
+ * NLBL_MGMT_A_IPV6MASK
+ *
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
*
* NLBL_MGMT_A_CV4DOI
@@ -68,13 +78,24 @@
* Required attributes:
*
* NLBL_MGMT_A_DOMAIN
+ *
+ * If the IP address selectors are not used the following attribute is
+ * required:
+ *
* NLBL_MGMT_A_PROTOCOL
*
- * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ * If the IP address selectors are used then the following attritbute is
+ * required:
+ *
+ * NLBL_MGMT_A_SELECTORLIST
+ *
+ * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ * attributes are required:
*
* NLBL_MGMT_A_CV4DOI
*
- * If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ * attributes are required.
*
* o ADDDEF:
* Sent by an application to set the default domain mapping for the NetLabel
@@ -100,15 +121,23 @@
* application there is no payload. On success the kernel should send a
* response using the following format.
*
- * Required attributes:
+ * If the IP address selectors are not used the following attribute is
+ * required:
*
* NLBL_MGMT_A_PROTOCOL
*
- * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
+ * If the IP address selectors are used then the following attritbute is
+ * required:
+ *
+ * NLBL_MGMT_A_SELECTORLIST
+ *
+ * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
+ * attributes are required:
*
* NLBL_MGMT_A_CV4DOI
*
- * If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
+ * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
+ * attributes are required.
*
* o PROTOCOLS:
* Sent by an application to request a list of configured NetLabel protocols
@@ -162,6 +191,26 @@ enum {
NLBL_MGMT_A_CV4DOI,
/* (NLA_U32)
* the CIPSOv4 DOI value */
+ NLBL_MGMT_A_IPV6ADDR,
+ /* (NLA_BINARY, struct in6_addr)
+ * an IPv6 address */
+ NLBL_MGMT_A_IPV6MASK,
+ /* (NLA_BINARY, struct in6_addr)
+ * an IPv6 address mask */
+ NLBL_MGMT_A_IPV4ADDR,
+ /* (NLA_BINARY, struct in_addr)
+ * an IPv4 address */
+ NLBL_MGMT_A_IPV4MASK,
+ /* (NLA_BINARY, struct in_addr)
+ * and IPv4 address mask */
+ NLBL_MGMT_A_ADDRSELECTOR,
+ /* (NLA_NESTED)
+ * an IP address selector, must contain an address, mask, and protocol
+ * attribute plus any protocol specific attributes */
+ NLBL_MGMT_A_SELECTORLIST,
+ /* (NLA_NESTED)
+ * the selector list, there must be at least one
+ * NLBL_MGMT_A_ADDRSELECTOR attribute */
__NLBL_MGMT_A_MAX,
};
#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 921c118ead8..e8a5c32b0f1 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -10,7 +10,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
*
* 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
@@ -54,6 +54,7 @@
#include <asm/atomic.h>
#include "netlabel_user.h"
+#include "netlabel_addrlist.h"
#include "netlabel_domainhash.h"
#include "netlabel_unlabeled.h"
#include "netlabel_mgmt.h"
@@ -76,22 +77,20 @@ struct netlbl_unlhsh_tbl {
struct list_head *tbl;
u32 size;
};
+#define netlbl_unlhsh_addr4_entry(iter) \
+ container_of(iter, struct netlbl_unlhsh_addr4, list)
struct netlbl_unlhsh_addr4 {
- __be32 addr;
- __be32 mask;
u32 secid;
- u32 valid;
- struct list_head list;
+ struct netlbl_af4list list;
struct rcu_head rcu;
};
+#define netlbl_unlhsh_addr6_entry(iter) \
+ container_of(iter, struct netlbl_unlhsh_addr6, list)
struct netlbl_unlhsh_addr6 {
- struct in6_addr addr;
- struct in6_addr mask;
u32 secid;
- u32 valid;
- struct list_head list;
+ struct netlbl_af6list list;
struct rcu_head rcu;
};
struct netlbl_unlhsh_iface {
@@ -147,76 +146,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
};
/*
- * Audit Helper Functions
- */
-
-/**
- * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv4 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
- const char *dev,
- __be32 addr, __be32 mask)
-{
- u32 mask_val = ntohl(mask);
-
- if (dev != NULL)
- audit_log_format(audit_buf, " netif=%s", dev);
- audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
- if (mask_val != 0xffffffff) {
- u32 mask_len = 0;
- while (mask_val > 0) {
- mask_val <<= 1;
- mask_len++;
- }
- audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
- }
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
- * @audit_buf: audit buffer
- * @dev: network interface
- * @addr: IP address
- * @mask: IP address mask
- *
- * Description:
- * Write the IPv6 address and address mask, if necessary, to @audit_buf.
- *
- */
-static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
- const char *dev,
- const struct in6_addr *addr,
- const struct in6_addr *mask)
-{
- if (dev != NULL)
- audit_log_format(audit_buf, " netif=%s", dev);
- audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
- if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
- u32 mask_len = 0;
- u32 mask_val;
- int iter = -1;
- while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
- mask_len += 32;
- mask_val = ntohl(mask->s6_addr32[iter]);
- while (mask_val > 0) {
- mask_val <<= 1;
- mask_len++;
- }
- audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
- }
-}
-#endif /* IPv6 */
-
-/*
* Unlabeled Connection Hash Table Functions
*/
@@ -274,26 +203,28 @@ static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
{
struct netlbl_unlhsh_iface *iface;
- struct netlbl_unlhsh_addr4 *iter4;
- struct netlbl_unlhsh_addr4 *tmp4;
- struct netlbl_unlhsh_addr6 *iter6;
- struct netlbl_unlhsh_addr6 *tmp6;
+ struct netlbl_af4list *iter4;
+ struct netlbl_af4list *tmp4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct netlbl_af6list *iter6;
+ struct netlbl_af6list *tmp6;
+#endif /* IPv6 */
iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
/* no need for locks here since we are the only one with access to this
* structure */
- list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list)
- if (iter4->valid) {
- list_del_rcu(&iter4->list);
- kfree(iter4);
- }
- list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list)
- if (iter6->valid) {
- list_del_rcu(&iter6->list);
- kfree(iter6);
- }
+ netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
+ netlbl_af4list_remove_entry(iter4);
+ kfree(netlbl_unlhsh_addr4_entry(iter4));
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
+ netlbl_af6list_remove_entry(iter6);
+ kfree(netlbl_unlhsh_addr6_entry(iter6));
+ }
+#endif /* IPv6 */
kfree(iface);
}
@@ -316,59 +247,6 @@ static u32 netlbl_unlhsh_hash(int ifindex)
}
/**
- * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
- * @addr: IPv4 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv4 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned. The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
- __be32 addr,
- const struct netlbl_unlhsh_iface *iface)
-{
- struct netlbl_unlhsh_addr4 *iter;
-
- list_for_each_entry_rcu(iter, &iface->addr4_list, list)
- if (iter->valid && (addr & iter->mask) == iter->addr)
- return iter;
-
- return NULL;
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-/**
- * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
- * @addr: IPv6 address
- * @iface: the network interface entry
- *
- * Description:
- * Searches the IPv6 address list of the network interface specified by @iface.
- * If a matching address entry is found it is returned, otherwise NULL is
- * returned. The caller is responsible for calling the rcu_read_[un]lock()
- * functions.
- *
- */
-static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
- const struct in6_addr *addr,
- const struct netlbl_unlhsh_iface *iface)
-{
- struct netlbl_unlhsh_addr6 *iter;
-
- list_for_each_entry_rcu(iter, &iface->addr6_list, list)
- if (iter->valid &&
- ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
- return iter;
-
- return NULL;
-}
-#endif /* IPv6 */
-
-/**
* netlbl_unlhsh_search_iface - Search for a matching interface entry
* @ifindex: the network interface
*
@@ -381,12 +259,12 @@ static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
{
u32 bkt;
+ struct list_head *bkt_list;
struct netlbl_unlhsh_iface *iter;
bkt = netlbl_unlhsh_hash(ifindex);
- list_for_each_entry_rcu(iter,
- &rcu_dereference(netlbl_unlhsh)->tbl[bkt],
- list)
+ bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt];
+ list_for_each_entry_rcu(iter, bkt_list, list)
if (iter->valid && iter->ifindex == ifindex)
return iter;
@@ -439,43 +317,26 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
const struct in_addr *mask,
u32 secid)
{
+ int ret_val;
struct netlbl_unlhsh_addr4 *entry;
- struct netlbl_unlhsh_addr4 *iter;
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (entry == NULL)
return -ENOMEM;
- entry->addr = addr->s_addr & mask->s_addr;
- entry->mask = mask->s_addr;
- entry->secid = secid;
- entry->valid = 1;
+ entry->list.addr = addr->s_addr & mask->s_addr;
+ entry->list.mask = mask->s_addr;
+ entry->list.valid = 1;
INIT_RCU_HEAD(&entry->rcu);
+ entry->secid = secid;
spin_lock(&netlbl_unlhsh_lock);
- iter = netlbl_unlhsh_search_addr4(entry->addr, iface);
- if (iter != NULL &&
- iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
- spin_unlock(&netlbl_unlhsh_lock);
- kfree(entry);
- return -EEXIST;
- }
- /* in order to speed up address searches through the list (the common
- * case) we need to keep the list in order based on the size of the
- * address mask such that the entry with the widest mask (smallest
- * numerical value) appears first in the list */
- list_for_each_entry_rcu(iter, &iface->addr4_list, list)
- if (iter->valid &&
- ntohl(entry->mask) > ntohl(iter->mask)) {
- __list_add_rcu(&entry->list,
- iter->list.prev,
- &iter->list);
- spin_unlock(&netlbl_unlhsh_lock);
- return 0;
- }
- list_add_tail_rcu(&entry->list, &iface->addr4_list);
+ ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
spin_unlock(&netlbl_unlhsh_lock);
- return 0;
+
+ if (ret_val != 0)
+ kfree(entry);
+ return ret_val;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -498,47 +359,29 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
const struct in6_addr *mask,
u32 secid)
{
+ int ret_val;
struct netlbl_unlhsh_addr6 *entry;
- struct netlbl_unlhsh_addr6 *iter;
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (entry == NULL)
return -ENOMEM;
- ipv6_addr_copy(&entry->addr, addr);
- entry->addr.s6_addr32[0] &= mask->s6_addr32[0];
- entry->addr.s6_addr32[1] &= mask->s6_addr32[1];
- entry->addr.s6_addr32[2] &= mask->s6_addr32[2];
- entry->addr.s6_addr32[3] &= mask->s6_addr32[3];
- ipv6_addr_copy(&entry->mask, mask);
- entry->secid = secid;
- entry->valid = 1;
+ ipv6_addr_copy(&entry->list.addr, addr);
+ entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
+ entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
+ entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
+ entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
+ ipv6_addr_copy(&entry->list.mask, mask);
+ entry->list.valid = 1;
INIT_RCU_HEAD(&entry->rcu);
+ entry->secid = secid;
spin_lock(&netlbl_unlhsh_lock);
- iter = netlbl_unlhsh_search_addr6(&entry->addr, iface);
- if (iter != NULL &&
- (ipv6_addr_equal(&iter->addr, addr) &&
- ipv6_addr_equal(&iter->mask, mask))) {
- spin_unlock(&netlbl_unlhsh_lock);
- kfree(entry);
- return -EEXIST;
- }
- /* in order to speed up address searches through the list (the common
- * case) we need to keep the list in order based on the size of the
- * address mask such that the entry with the widest mask (smallest
- * numerical value) appears first in the list */
- list_for_each_entry_rcu(iter, &iface->addr6_list, list)
- if (iter->valid &&
- ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
- __list_add_rcu(&entry->list,
- iter->list.prev,
- &iter->list);
- spin_unlock(&netlbl_unlhsh_lock);
- return 0;
- }
- list_add_tail_rcu(&entry->list, &iface->addr6_list);
+ ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
spin_unlock(&netlbl_unlhsh_lock);
+
+ if (ret_val != 0)
+ kfree(entry);
return 0;
}
#endif /* IPv6 */
@@ -658,10 +501,10 @@ static int netlbl_unlhsh_add(struct net *net,
mask4 = (struct in_addr *)mask;
ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
if (audit_buf != NULL)
- netlbl_unlabel_audit_addr4(audit_buf,
- dev_name,
- addr4->s_addr,
- mask4->s_addr);
+ netlbl_af4list_audit_addr(audit_buf, 1,
+ dev_name,
+ addr4->s_addr,
+ mask4->s_addr);
break;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -672,9 +515,9 @@ static int netlbl_unlhsh_add(struct net *net,
mask6 = (struct in6_addr *)mask;
ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
if (audit_buf != NULL)
- netlbl_unlabel_audit_addr6(audit_buf,
- dev_name,
- addr6, mask6);
+ netlbl_af6list_audit_addr(audit_buf, 1,
+ dev_name,
+ addr6, mask6);
break;
}
#endif /* IPv6 */
@@ -719,35 +562,34 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
const struct in_addr *mask,
struct netlbl_audit *audit_info)
{
- int ret_val = -ENOENT;
+ int ret_val = 0;
+ struct netlbl_af4list *list_entry;
struct netlbl_unlhsh_addr4 *entry;
- struct audit_buffer *audit_buf = NULL;
+ struct audit_buffer *audit_buf;
struct net_device *dev;
- char *secctx = NULL;
+ char *secctx;
u32 secctx_len;
spin_lock(&netlbl_unlhsh_lock);
- entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface);
- if (entry != NULL &&
- entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
- entry->valid = 0;
- list_del_rcu(&entry->list);
- ret_val = 0;
- }
+ list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
+ &iface->addr4_list);
spin_unlock(&netlbl_unlhsh_lock);
+ if (list_entry == NULL)
+ ret_val = -ENOENT;
+ entry = netlbl_unlhsh_addr4_entry(list_entry);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
audit_info);
if (audit_buf != NULL) {
dev = dev_get_by_index(net, iface->ifindex);
- netlbl_unlabel_audit_addr4(audit_buf,
- (dev != NULL ? dev->name : NULL),
- entry->addr, entry->mask);
+ netlbl_af4list_audit_addr(audit_buf, 1,
+ (dev != NULL ? dev->name : NULL),
+ addr->s_addr, mask->s_addr);
if (dev != NULL)
dev_put(dev);
- if (security_secid_to_secctx(entry->secid,
- &secctx,
- &secctx_len) == 0) {
+ if (entry && security_secid_to_secctx(entry->secid,
+ &secctx,
+ &secctx_len) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", secctx);
security_release_secctx(secctx, secctx_len);
}
@@ -781,36 +623,33 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
const struct in6_addr *mask,
struct netlbl_audit *audit_info)
{
- int ret_val = -ENOENT;
+ int ret_val = 0;
+ struct netlbl_af6list *list_entry;
struct netlbl_unlhsh_addr6 *entry;
- struct audit_buffer *audit_buf = NULL;
+ struct audit_buffer *audit_buf;
struct net_device *dev;
- char *secctx = NULL;
+ char *secctx;
u32 secctx_len;
spin_lock(&netlbl_unlhsh_lock);
- entry = netlbl_unlhsh_search_addr6(addr, iface);
- if (entry != NULL &&
- (ipv6_addr_equal(&entry->addr, addr) &&
- ipv6_addr_equal(&entry->mask, mask))) {
- entry->valid = 0;
- list_del_rcu(&entry->list);
- ret_val = 0;
- }
+ list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
spin_unlock(&netlbl_unlhsh_lock);
+ if (list_entry == NULL)
+ ret_val = -ENOENT;
+ entry = netlbl_unlhsh_addr6_entry(list_entry);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
audit_info);
if (audit_buf != NULL) {
dev = dev_get_by_index(net, iface->ifindex);
- netlbl_unlabel_audit_addr6(audit_buf,
- (dev != NULL ? dev->name : NULL),
- addr, mask);
+ netlbl_af6list_audit_addr(audit_buf, 1,
+ (dev != NULL ? dev->name : NULL),
+ addr, mask);
if (dev != NULL)
dev_put(dev);
- if (security_secid_to_secctx(entry->secid,
- &secctx,
- &secctx_len) == 0) {
+ if (entry && security_secid_to_secctx(entry->secid,
+ &secctx,
+ &secctx_len) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", secctx);
security_release_secctx(secctx, secctx_len);
}
@@ -836,16 +675,18 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
*/
static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
{
- struct netlbl_unlhsh_addr4 *iter4;
- struct netlbl_unlhsh_addr6 *iter6;
+ struct netlbl_af4list *iter4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct netlbl_af6list *iter6;
+#endif /* IPv6 */
spin_lock(&netlbl_unlhsh_lock);
- list_for_each_entry_rcu(iter4, &iface->addr4_list, list)
- if (iter4->valid)
- goto unlhsh_condremove_failure;
- list_for_each_entry_rcu(iter6, &iface->addr6_list, list)
- if (iter6->valid)
- goto unlhsh_condremove_failure;
+ netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
+ goto unlhsh_condremove_failure;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
+ goto unlhsh_condremove_failure;
+#endif /* IPv6 */
iface->valid = 0;
if (iface->ifindex > 0)
list_del_rcu(&iface->list);
@@ -1349,7 +1190,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
if (addr4) {
struct in_addr addr_struct;
- addr_struct.s_addr = addr4->addr;
+ addr_struct.s_addr = addr4->list.addr;
ret_val = nla_put(cb_arg->skb,
NLBL_UNLABEL_A_IPV4ADDR,
sizeof(struct in_addr),
@@ -1357,7 +1198,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
if (ret_val != 0)
goto list_cb_failure;
- addr_struct.s_addr = addr4->mask;
+ addr_struct.s_addr = addr4->list.mask;
ret_val = nla_put(cb_arg->skb,
NLBL_UNLABEL_A_IPV4MASK,
sizeof(struct in_addr),
@@ -1370,14 +1211,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
ret_val = nla_put(cb_arg->skb,
NLBL_UNLABEL_A_IPV6ADDR,
sizeof(struct in6_addr),
- &addr6->addr);
+ &addr6->list.addr);
if (ret_val != 0)
goto list_cb_failure;
ret_val = nla_put(cb_arg->skb,
NLBL_UNLABEL_A_IPV6MASK,
sizeof(struct in6_addr),
- &addr6->mask);
+ &addr6->list.mask);
if (ret_val != 0)
goto list_cb_failure;
@@ -1425,8 +1266,11 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
u32 iter_bkt;
u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
struct netlbl_unlhsh_iface *iface;
- struct netlbl_unlhsh_addr4 *addr4;
- struct netlbl_unlhsh_addr6 *addr6;
+ struct list_head *iter_list;
+ struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct netlbl_af6list *addr6;
+#endif
cb_arg.nl_cb = cb;
cb_arg.skb = skb;
@@ -1436,44 +1280,43 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
for (iter_bkt = skip_bkt;
iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
- list_for_each_entry_rcu(iface,
- &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt],
- list) {
+ iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
+ list_for_each_entry_rcu(iface, iter_list, list) {
if (!iface->valid ||
iter_chain++ < skip_chain)
continue;
- list_for_each_entry_rcu(addr4,
- &iface->addr4_list,
- list) {
- if (!addr4->valid || iter_addr4++ < skip_addr4)
+ netlbl_af4list_foreach_rcu(addr4,
+ &iface->addr4_list) {
+ if (iter_addr4++ < skip_addr4)
continue;
if (netlbl_unlabel_staticlist_gen(
- NLBL_UNLABEL_C_STATICLIST,
- iface,
- addr4,
- NULL,
- &cb_arg) < 0) {
+ NLBL_UNLABEL_C_STATICLIST,
+ iface,
+ netlbl_unlhsh_addr4_entry(addr4),
+ NULL,
+ &cb_arg) < 0) {
iter_addr4--;
iter_chain--;
goto unlabel_staticlist_return;
}
}
- list_for_each_entry_rcu(addr6,
- &iface->addr6_list,
- list) {
- if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_rcu(addr6,
+ &iface->addr6_list) {
+ if (iter_addr6++ < skip_addr6)
continue;
if (netlbl_unlabel_staticlist_gen(
- NLBL_UNLABEL_C_STATICLIST,
- iface,
- NULL,
- addr6,
- &cb_arg) < 0) {
+ NLBL_UNLABEL_C_STATICLIST,
+ iface,
+ NULL,
+ netlbl_unlhsh_addr6_entry(addr6),
+ &cb_arg) < 0) {
iter_addr6--;
iter_chain--;
goto unlabel_staticlist_return;
}
}
+#endif /* IPv6 */
}
}
@@ -1504,9 +1347,12 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
struct netlbl_unlhsh_iface *iface;
u32 skip_addr4 = cb->args[0];
u32 skip_addr6 = cb->args[1];
- u32 iter_addr4 = 0, iter_addr6 = 0;
- struct netlbl_unlhsh_addr4 *addr4;
- struct netlbl_unlhsh_addr6 *addr6;
+ u32 iter_addr4 = 0;
+ struct netlbl_af4list *addr4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ u32 iter_addr6 = 0;
+ struct netlbl_af6list *addr6;
+#endif
cb_arg.nl_cb = cb;
cb_arg.skb = skb;
@@ -1517,30 +1363,32 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
if (iface == NULL || !iface->valid)
goto unlabel_staticlistdef_return;
- list_for_each_entry_rcu(addr4, &iface->addr4_list, list) {
- if (!addr4->valid || iter_addr4++ < skip_addr4)
+ netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
+ if (iter_addr4++ < skip_addr4)
continue;
if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
- iface,
- addr4,
- NULL,
- &cb_arg) < 0) {
+ iface,
+ netlbl_unlhsh_addr4_entry(addr4),
+ NULL,
+ &cb_arg) < 0) {
iter_addr4--;
goto unlabel_staticlistdef_return;
}
}
- list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
- if (!addr6->valid || iter_addr6++ < skip_addr6)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
+ if (iter_addr6++ < skip_addr6)
continue;
if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
- iface,
- NULL,
- addr6,
- &cb_arg) < 0) {
+ iface,
+ NULL,
+ netlbl_unlhsh_addr6_entry(addr6),
+ &cb_arg) < 0) {
iter_addr6--;
goto unlabel_staticlistdef_return;
}
}
+#endif /* IPv6 */
unlabel_staticlistdef_return:
rcu_read_unlock();
@@ -1718,25 +1566,27 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
switch (family) {
case PF_INET: {
struct iphdr *hdr4;
- struct netlbl_unlhsh_addr4 *addr4;
+ struct netlbl_af4list *addr4;
hdr4 = ip_hdr(skb);
- addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface);
+ addr4 = netlbl_af4list_search(hdr4->saddr,
+ &iface->addr4_list);
if (addr4 == NULL)
goto unlabel_getattr_nolabel;
- secattr->attr.secid = addr4->secid;
+ secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
break;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case PF_INET6: {
struct ipv6hdr *hdr6;
- struct netlbl_unlhsh_addr6 *addr6;
+ struct netlbl_af6list *addr6;
hdr6 = ipv6_hdr(skb);
- addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface);
+ addr6 = netlbl_af6list_search(&hdr6->saddr,
+ &iface->addr6_list);
if (addr6 == NULL)
goto unlabel_getattr_nolabel;
- secattr->attr.secid = addr6->secid;
+ secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
break;
}
#endif /* IPv6 */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 5cadbeb76a1..24fdd4cd22c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -13,7 +13,6 @@
#include <linux/debugfs.h>
#include <linux/notifier.h>
#include <linux/device.h>
-#include <linux/list.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
#include <net/wireless.h>
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index d64e6badc94..982dcae7bbe 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -105,12 +105,12 @@ as-instr = $(call try-run,\
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
cc-option = $(call try-run,\
- $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",$(1),$(2))
+ $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
# cc-option-yn
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
cc-option-yn = $(call try-run,\
- $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
+ $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
# cc-option-align
# Prefix align with either -falign or -malign
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 4c9890ec252..473f94e56ea 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -629,6 +629,59 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
return 1;
}
+static const struct dmifield {
+ const char *prefix;
+ int field;
+} dmi_fields[] = {
+ { "bvn", DMI_BIOS_VENDOR },
+ { "bvr", DMI_BIOS_VERSION },
+ { "bd", DMI_BIOS_DATE },
+ { "svn", DMI_SYS_VENDOR },
+ { "pn", DMI_PRODUCT_NAME },
+ { "pvr", DMI_PRODUCT_VERSION },
+ { "rvn", DMI_BOARD_VENDOR },
+ { "rn", DMI_BOARD_NAME },
+ { "rvr", DMI_BOARD_VERSION },
+ { "cvn", DMI_CHASSIS_VENDOR },
+ { "ct", DMI_CHASSIS_TYPE },
+ { "cvr", DMI_CHASSIS_VERSION },
+ { NULL, DMI_NONE }
+};
+
+static void dmi_ascii_filter(char *d, const char *s)
+{
+ /* Filter out characters we don't want to see in the modalias string */
+ for (; *s; s++)
+ if (*s > ' ' && *s < 127 && *s != ':')
+ *(d++) = *s;
+
+ *d = 0;
+}
+
+
+static int do_dmi_entry(const char *filename, struct dmi_system_id *id,
+ char *alias)
+{
+ int i, j;
+
+ sprintf(alias, "dmi*");
+
+ for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
+ for (j = 0; j < 4; j++) {
+ if (id->matches[j].slot &&
+ id->matches[j].slot == dmi_fields[i].field) {
+ sprintf(alias + strlen(alias), ":%s*",
+ dmi_fields[i].prefix);
+ dmi_ascii_filter(alias + strlen(alias),
+ id->matches[j].substr);
+ strcat(alias, "*");
+ }
+ }
+ }
+
+ strcat(alias, ":");
+ return 1;
+}
/* Ignore any prefix, eg. some architectures prepend _ */
static inline int sym_is(const char *symbol, const char *name)
{
@@ -760,6 +813,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
do_table(symval, sym->st_size,
sizeof(struct i2c_device_id), "i2c",
do_i2c_entry, mod);
+ else if (sym_is(symname, "__mod_dmi_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct dmi_system_id), "dmi",
+ do_dmi_entry, mod);
free(zeros);
}
diff --git a/security/inode.c b/security/inode.c
index ca4958ebad8..efea5a60546 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -20,8 +20,7 @@
#include <linux/init.h>
#include <linux/namei.h>
#include <linux/security.h>
-
-#define SECURITYFS_MAGIC 0x73636673
+#include <linux/magic.h>
static struct vfsmount *mount;
static int mount_count;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4a7374c12d9..576e5119907 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk)
struct sk_security_struct *ssec = sk->sk_security;
sk->sk_security = NULL;
+ selinux_netlbl_sk_security_free(ssec);
kfree(ssec);
}
@@ -324,7 +325,7 @@ enum {
Opt_rootcontext = 4,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_context, CONTEXT_STR "%s"},
{Opt_fscontext, FSCONTEXT_STR "%s"},
{Opt_defcontext, DEFCONTEXT_STR "%s"},
@@ -2121,7 +2122,6 @@ static inline void flush_unauthorized_files(struct files_struct *files)
long j = -1;
int drop_tty = 0;
- mutex_lock(&tty_mutex);
tty = get_current_tty();
if (tty) {
file_list_lock();
@@ -2139,8 +2139,8 @@ static inline void flush_unauthorized_files(struct files_struct *files)
}
}
file_list_unlock();
+ tty_kref_put(tty);
}
- mutex_unlock(&tty_mutex);
/* Reset controlling tty. */
if (drop_tty)
no_tty();
@@ -3801,6 +3801,7 @@ out:
static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
+ struct sock *sk = sock->sk;
struct inode_security_struct *isec;
int err;
@@ -3814,7 +3815,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
isec = SOCK_INODE(sock)->i_security;
if (isec->sclass == SECCLASS_TCP_SOCKET ||
isec->sclass == SECCLASS_DCCP_SOCKET) {
- struct sock *sk = sock->sk;
struct avc_audit_data ad;
struct sockaddr_in *addr4 = NULL;
struct sockaddr_in6 *addr6 = NULL;
@@ -3848,6 +3848,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
goto out;
}
+ err = selinux_netlbl_socket_connect(sk, address);
+
out:
return err;
}
@@ -4077,20 +4079,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
}
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
- struct avc_audit_data *ad,
- u16 family, char *addrp)
+ u16 family)
{
int err;
struct sk_security_struct *sksec = sk->sk_security;
u32 peer_sid;
u32 sk_sid = sksec->sid;
+ struct avc_audit_data ad;
+ char *addrp;
+
+ AVC_AUDIT_DATA_INIT(&ad, NET);
+ ad.u.net.netif = skb->iif;
+ ad.u.net.family = family;
+ err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
+ if (err)
+ return err;
if (selinux_compat_net)
- err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad,
+ err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
family, addrp);
else
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
- PACKET__RECV, ad);
+ PACKET__RECV, &ad);
if (err)
return err;
@@ -4099,12 +4109,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
if (err)
return err;
err = avc_has_perm(sk_sid, peer_sid,
- SECCLASS_PEER, PEER__RECV, ad);
+ SECCLASS_PEER, PEER__RECV, &ad);
+ if (err)
+ selinux_netlbl_err(skb, err, 0);
} else {
- err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad);
+ err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
if (err)
return err;
- err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad);
+ err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
}
return err;
@@ -4118,6 +4130,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
u32 sk_sid = sksec->sid;
struct avc_audit_data ad;
char *addrp;
+ u8 secmark_active;
+ u8 peerlbl_active;
if (family != PF_INET && family != PF_INET6)
return 0;
@@ -4126,6 +4140,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
family = PF_INET;
+ /* If any sort of compatibility mode is enabled then handoff processing
+ * to the selinux_sock_rcv_skb_compat() function to deal with the
+ * special handling. We do this in an attempt to keep this function
+ * as fast and as clean as possible. */
+ if (selinux_compat_net || !selinux_policycap_netpeer)
+ return selinux_sock_rcv_skb_compat(sk, skb, family);
+
+ secmark_active = selinux_secmark_enabled();
+ peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+ if (!secmark_active && !peerlbl_active)
+ return 0;
+
AVC_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.netif = skb->iif;
ad.u.net.family = family;
@@ -4133,15 +4159,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (err)
return err;
- /* If any sort of compatibility mode is enabled then handoff processing
- * to the selinux_sock_rcv_skb_compat() function to deal with the
- * special handling. We do this in an attempt to keep this function
- * as fast and as clean as possible. */
- if (selinux_compat_net || !selinux_policycap_netpeer)
- return selinux_sock_rcv_skb_compat(sk, skb, &ad,
- family, addrp);
-
- if (netlbl_enabled() || selinux_xfrm_enabled()) {
+ if (peerlbl_active) {
u32 peer_sid;
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4149,13 +4167,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
peer_sid, &ad);
- if (err)
+ if (err) {
+ selinux_netlbl_err(skb, err, 0);
return err;
+ }
err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
PEER__RECV, &ad);
+ if (err)
+ selinux_netlbl_err(skb, err, 0);
}
- if (selinux_secmark_enabled()) {
+ if (secmark_active) {
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
@@ -4214,10 +4236,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
u32 peer_secid = SECSID_NULL;
u16 family;
- if (sock)
+ if (skb && skb->protocol == htons(ETH_P_IP))
+ family = PF_INET;
+ else if (skb && skb->protocol == htons(ETH_P_IPV6))
+ family = PF_INET6;
+ else if (sock)
family = sock->sk->sk_family;
- else if (skb && skb->sk)
- family = skb->sk->sk_family;
else
goto out;
@@ -4275,8 +4299,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
sk->sk_family == PF_UNIX)
isec->sid = sksec->sid;
sksec->sclass = isec->sclass;
-
- selinux_netlbl_sock_graft(sk, parent);
}
static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
@@ -4284,10 +4306,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
{
struct sk_security_struct *sksec = sk->sk_security;
int err;
+ u16 family = sk->sk_family;
u32 newsid;
u32 peersid;
- err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid);
+ /* handle mapped IPv4 packets arriving via IPv6 sockets */
+ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+ family = PF_INET;
+
+ err = selinux_skb_peerlbl_sid(skb, family, &peersid);
if (err)
return err;
if (peersid == SECSID_NULL) {
@@ -4322,12 +4349,18 @@ static void selinux_inet_csk_clone(struct sock *newsk,
selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
}
-static void selinux_inet_conn_established(struct sock *sk,
- struct sk_buff *skb)
+static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
{
+ u16 family = sk->sk_family;
struct sk_security_struct *sksec = sk->sk_security;
- selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid);
+ /* handle mapped IPv4 packets arriving via IPv6 sockets */
+ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+ family = PF_INET;
+
+ selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
+
+ selinux_netlbl_inet_conn_established(sk, family);
}
static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4377,39 +4410,54 @@ out:
static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
u16 family)
{
+ int err;
char *addrp;
u32 peer_sid;
struct avc_audit_data ad;
u8 secmark_active;
+ u8 netlbl_active;
u8 peerlbl_active;
if (!selinux_policycap_netpeer)
return NF_ACCEPT;
secmark_active = selinux_secmark_enabled();
- peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+ netlbl_active = netlbl_enabled();
+ peerlbl_active = netlbl_active || selinux_xfrm_enabled();
if (!secmark_active && !peerlbl_active)
return NF_ACCEPT;
+ if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
+ return NF_DROP;
+
AVC_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.netif = ifindex;
ad.u.net.family = family;
if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
return NF_DROP;
- if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
- return NF_DROP;
-
- if (peerlbl_active)
- if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
- peer_sid, &ad) != 0)
+ if (peerlbl_active) {
+ err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
+ peer_sid, &ad);
+ if (err) {
+ selinux_netlbl_err(skb, err, 1);
return NF_DROP;
+ }
+ }
if (secmark_active)
if (avc_has_perm(peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;
+ if (netlbl_active)
+ /* we do this in the FORWARD path and not the POST_ROUTING
+ * path because we want to make sure we apply the necessary
+ * labeling before IPsec is applied so we can leverage AH
+ * protection */
+ if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
+ return NF_DROP;
+
return NF_ACCEPT;
}
@@ -4433,6 +4481,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
}
#endif /* IPV6 */
+static unsigned int selinux_ip_output(struct sk_buff *skb,
+ u16 family)
+{
+ u32 sid;
+
+ if (!netlbl_enabled())
+ return NF_ACCEPT;
+
+ /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
+ * because we want to make sure we apply the necessary labeling
+ * before IPsec is applied so we can leverage AH protection */
+ if (skb->sk) {
+ struct sk_security_struct *sksec = skb->sk->sk_security;
+ sid = sksec->sid;
+ } else
+ sid = SECINITSID_KERNEL;
+ if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
+ return NF_DROP;
+
+ return NF_ACCEPT;
+}
+
+static unsigned int selinux_ipv4_output(unsigned int hooknum,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return selinux_ip_output(skb, PF_INET);
+}
+
static int selinux_ip_postroute_iptables_compat(struct sock *sk,
int ifindex,
struct avc_audit_data *ad,
@@ -4500,30 +4579,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
int ifindex,
- struct avc_audit_data *ad,
- u16 family,
- char *addrp,
- u8 proto)
+ u16 family)
{
struct sock *sk = skb->sk;
struct sk_security_struct *sksec;
+ struct avc_audit_data ad;
+ char *addrp;
+ u8 proto;
if (sk == NULL)
return NF_ACCEPT;
sksec = sk->sk_security;
+ AVC_AUDIT_DATA_INIT(&ad, NET);
+ ad.u.net.netif = ifindex;
+ ad.u.net.family = family;
+ if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
+ return NF_DROP;
+
if (selinux_compat_net) {
if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
- ad, family, addrp))
+ &ad, family, addrp))
return NF_DROP;
} else {
if (avc_has_perm(sksec->sid, skb->secmark,
- SECCLASS_PACKET, PACKET__SEND, ad))
+ SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP;
}
if (selinux_policycap_netpeer)
- if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
+ if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
return NF_DROP;
return NF_ACCEPT;
@@ -4537,23 +4622,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
struct sock *sk;
struct avc_audit_data ad;
char *addrp;
- u8 proto;
u8 secmark_active;
u8 peerlbl_active;
- AVC_AUDIT_DATA_INIT(&ad, NET);
- ad.u.net.netif = ifindex;
- ad.u.net.family = family;
- if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
- return NF_DROP;
-
/* If any sort of compatibility mode is enabled then handoff processing
* to the selinux_ip_postroute_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
if (selinux_compat_net || !selinux_policycap_netpeer)
- return selinux_ip_postroute_compat(skb, ifindex, &ad,
- family, addrp, proto);
+ return selinux_ip_postroute_compat(skb, ifindex, family);
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
* packet transformation so allow the packet to pass without any checks
@@ -4569,21 +4646,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
if (!secmark_active && !peerlbl_active)
return NF_ACCEPT;
- /* if the packet is locally generated (skb->sk != NULL) then use the
- * socket's label as the peer label, otherwise the packet is being
- * forwarded through this system and we need to fetch the peer label
- * directly from the packet */
+ /* if the packet is being forwarded then get the peer label from the
+ * packet itself; otherwise check to see if it is from a local
+ * application or the kernel, if from an application get the peer label
+ * from the sending socket, otherwise use the kernel's sid */
sk = skb->sk;
- if (sk) {
+ if (sk == NULL) {
+ switch (family) {
+ case PF_INET:
+ if (IPCB(skb)->flags & IPSKB_FORWARDED)
+ secmark_perm = PACKET__FORWARD_OUT;
+ else
+ secmark_perm = PACKET__SEND;
+ break;
+ case PF_INET6:
+ if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
+ secmark_perm = PACKET__FORWARD_OUT;
+ else
+ secmark_perm = PACKET__SEND;
+ break;
+ default:
+ return NF_DROP;
+ }
+ if (secmark_perm == PACKET__FORWARD_OUT) {
+ if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
+ return NF_DROP;
+ } else
+ peer_sid = SECINITSID_KERNEL;
+ } else {
struct sk_security_struct *sksec = sk->sk_security;
peer_sid = sksec->sid;
secmark_perm = PACKET__SEND;
- } else {
- if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
- return NF_DROP;
- secmark_perm = PACKET__FORWARD_OUT;
}
+ AVC_AUDIT_DATA_INIT(&ad, NET);
+ ad.u.net.netif = ifindex;
+ ad.u.net.family = family;
+ if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
+ return NF_DROP;
+
if (secmark_active)
if (avc_has_perm(peer_sid, skb->secmark,
SECCLASS_PACKET, secmark_perm, &ad))
@@ -5657,6 +5758,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_SELINUX_FIRST,
+ },
+ {
+ .hook = selinux_ipv4_output,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP_PRI_SELINUX_FIRST,
}
};
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 487a7d81fe2..b913c8d0603 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -39,6 +39,9 @@
#ifdef CONFIG_NETLABEL
void selinux_netlbl_cache_invalidate(void);
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
+
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
int family);
@@ -46,8 +49,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
u32 *type,
u32 *sid);
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+ u16 family,
+ u32 sid);
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
int selinux_netlbl_socket_post_create(struct socket *sock);
int selinux_netlbl_inode_permission(struct inode *inode, int mask);
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
@@ -57,12 +63,27 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
int selinux_netlbl_socket_setsockopt(struct socket *sock,
int level,
int optname);
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr);
+
#else
static inline void selinux_netlbl_cache_invalidate(void)
{
return;
}
+static inline void selinux_netlbl_err(struct sk_buff *skb,
+ int error,
+ int gateway)
+{
+ return;
+}
+
+static inline void selinux_netlbl_sk_security_free(
+ struct sk_security_struct *ssec)
+{
+ return;
+}
+
static inline void selinux_netlbl_sk_security_reset(
struct sk_security_struct *ssec,
int family)
@@ -79,9 +100,21 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
*sid = SECSID_NULL;
return 0;
}
+static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+ u16 family,
+ u32 sid)
+{
+ return 0;
+}
-static inline void selinux_netlbl_sock_graft(struct sock *sk,
- struct socket *sock)
+static inline int selinux_netlbl_conn_setsid(struct sock *sk,
+ struct sockaddr *addr)
+{
+ return 0;
+}
+
+static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
+ u16 family)
{
return;
}
@@ -107,6 +140,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
{
return 0;
}
+static inline int selinux_netlbl_socket_connect(struct sock *sk,
+ struct sockaddr *addr)
+{
+ return 0;
+}
#endif /* CONFIG_NETLABEL */
#endif
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 91070ab874c..f8be8d7fa26 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -109,16 +109,19 @@ struct netport_security_struct {
};
struct sk_security_struct {
- u32 sid; /* SID of this object */
- u32 peer_sid; /* SID of peer */
- u16 sclass; /* sock security class */
#ifdef CONFIG_NETLABEL
enum { /* NetLabel state */
NLBL_UNSET = 0,
NLBL_REQUIRE,
NLBL_LABELED,
+ NLBL_REQSKB,
+ NLBL_CONNLABELED,
} nlbl_state;
+ struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */
#endif
+ u32 sid; /* SID of this object */
+ u32 peer_sid; /* SID of peer */
+ u16 sclass; /* sock security class */
};
struct key_security_struct {
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 89b418392f1..f58701a7b72 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -9,7 +9,7 @@
*/
/*
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
*
* 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
@@ -29,8 +29,12 @@
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
#include <net/sock.h>
#include <net/netlabel.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
#include "objsec.h"
#include "security.h"
@@ -64,32 +68,69 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
}
/**
+ * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
+ * @sk: the socket
+ *
+ * Description:
+ * Generate the NetLabel security attributes for a socket, making full use of
+ * the socket's attribute cache. Returns a pointer to the security attributes
+ * on success, NULL on failure.
+ *
+ */
+static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
+{
+ int rc;
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct netlbl_lsm_secattr *secattr;
+
+ if (sksec->nlbl_secattr != NULL)
+ return sksec->nlbl_secattr;
+
+ secattr = netlbl_secattr_alloc(GFP_ATOMIC);
+ if (secattr == NULL)
+ return NULL;
+ rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
+ if (rc != 0) {
+ netlbl_secattr_free(secattr);
+ return NULL;
+ }
+ sksec->nlbl_secattr = secattr;
+
+ return secattr;
+}
+
+/**
* selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
* @sk: the socket to label
- * @sid: the SID to use
*
* Description:
- * Attempt to label a socket using the NetLabel mechanism using the given
- * SID. Returns zero values on success, negative values on failure.
+ * Attempt to label a socket using the NetLabel mechanism. Returns zero values
+ * on success, negative values on failure.
*
*/
-static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
+static int selinux_netlbl_sock_setsid(struct sock *sk)
{
int rc;
struct sk_security_struct *sksec = sk->sk_security;
- struct netlbl_lsm_secattr secattr;
+ struct netlbl_lsm_secattr *secattr;
- netlbl_secattr_init(&secattr);
+ if (sksec->nlbl_state != NLBL_REQUIRE)
+ return 0;
- rc = security_netlbl_sid_to_secattr(sid, &secattr);
- if (rc != 0)
- goto sock_setsid_return;
- rc = netlbl_sock_setattr(sk, &secattr);
- if (rc == 0)
+ secattr = selinux_netlbl_sock_genattr(sk);
+ if (secattr == NULL)
+ return -ENOMEM;
+ rc = netlbl_sock_setattr(sk, secattr);
+ switch (rc) {
+ case 0:
sksec->nlbl_state = NLBL_LABELED;
+ break;
+ case -EDESTADDRREQ:
+ sksec->nlbl_state = NLBL_REQSKB;
+ rc = 0;
+ break;
+ }
-sock_setsid_return:
- netlbl_secattr_destroy(&secattr);
return rc;
}
@@ -106,6 +147,38 @@ void selinux_netlbl_cache_invalidate(void)
}
/**
+ * selinux_netlbl_err - Handle a NetLabel packet error
+ * @skb: the packet
+ * @error: the error code
+ * @gateway: true if host is acting as a gateway, false otherwise
+ *
+ * Description:
+ * When a packet is dropped due to a call to avc_has_perm() pass the error
+ * code to the NetLabel subsystem so any protocol specific processing can be
+ * done. This is safe to call even if you are unsure if NetLabel labeling is
+ * present on the packet, NetLabel is smart enough to only act when it should.
+ *
+ */
+void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
+{
+ netlbl_skbuff_err(skb, error, gateway);
+}
+
+/**
+ * selinux_netlbl_sk_security_free - Free the NetLabel fields
+ * @sssec: the sk_security_struct
+ *
+ * Description:
+ * Free all of the memory in the NetLabel fields of a sk_security_struct.
+ *
+ */
+void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
+{
+ if (ssec->nlbl_secattr != NULL)
+ netlbl_secattr_free(ssec->nlbl_secattr);
+}
+
+/**
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields
* @ssec: the sk_security_struct
* @family: the socket family
@@ -163,35 +236,118 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
}
/**
- * selinux_netlbl_sock_graft - Netlabel the new socket
+ * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
+ * @skb: the packet
+ * @family: protocol family
+ * @sid: the SID
+ *
+ * Description
+ * Call the NetLabel mechanism to set the label of a packet using @sid.
+ * Returns zero on auccess, negative values on failure.
+ *
+ */
+int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+ u16 family,
+ u32 sid)
+{
+ int rc;
+ struct netlbl_lsm_secattr secattr_storage;
+ struct netlbl_lsm_secattr *secattr = NULL;
+ struct sock *sk;
+
+ /* if this is a locally generated packet check to see if it is already
+ * being labeled by it's parent socket, if it is just exit */
+ sk = skb->sk;
+ if (sk != NULL) {
+ struct sk_security_struct *sksec = sk->sk_security;
+ if (sksec->nlbl_state != NLBL_REQSKB)
+ return 0;
+ secattr = sksec->nlbl_secattr;
+ }
+ if (secattr == NULL) {
+ secattr = &secattr_storage;
+ netlbl_secattr_init(secattr);
+ rc = security_netlbl_sid_to_secattr(sid, secattr);
+ if (rc != 0)
+ goto skbuff_setsid_return;
+ }
+
+ rc = netlbl_skbuff_setattr(skb, family, secattr);
+
+skbuff_setsid_return:
+ if (secattr == &secattr_storage)
+ netlbl_secattr_destroy(secattr);
+ return rc;
+}
+
+/**
+ * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
* @sk: the new connection
- * @sock: the new socket
*
* Description:
- * The connection represented by @sk is being grafted onto @sock so set the
- * socket's NetLabel to match the SID of @sk.
+ * A new connection has been established on @sk so make sure it is labeled
+ * correctly with the NetLabel susbsystem.
*
*/
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
+void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
{
+ int rc;
struct sk_security_struct *sksec = sk->sk_security;
- struct netlbl_lsm_secattr secattr;
- u32 nlbl_peer_sid;
+ struct netlbl_lsm_secattr *secattr;
+ struct inet_sock *sk_inet = inet_sk(sk);
+ struct sockaddr_in addr;
if (sksec->nlbl_state != NLBL_REQUIRE)
return;
- netlbl_secattr_init(&secattr);
- if (netlbl_sock_getattr(sk, &secattr) == 0 &&
- secattr.flags != NETLBL_SECATTR_NONE &&
- security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
- sksec->peer_sid = nlbl_peer_sid;
- netlbl_secattr_destroy(&secattr);
+ secattr = selinux_netlbl_sock_genattr(sk);
+ if (secattr == NULL)
+ return;
- /* Try to set the NetLabel on the socket to save time later, if we fail
- * here we will pick up the pieces in later calls to
- * selinux_netlbl_inode_permission(). */
- selinux_netlbl_sock_setsid(sk, sksec->sid);
+ rc = netlbl_sock_setattr(sk, secattr);
+ switch (rc) {
+ case 0:
+ sksec->nlbl_state = NLBL_LABELED;
+ break;
+ case -EDESTADDRREQ:
+ /* no PF_INET6 support yet because we don't support any IPv6
+ * labeling protocols */
+ if (family != PF_INET) {
+ sksec->nlbl_state = NLBL_UNSET;
+ return;
+ }
+
+ addr.sin_family = family;
+ addr.sin_addr.s_addr = sk_inet->daddr;
+ if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
+ secattr) != 0) {
+ /* we failed to label the connected socket (could be
+ * for a variety of reasons, the actual "why" isn't
+ * important here) so we have to go to our backup plan,
+ * labeling the packets individually in the netfilter
+ * local output hook. this is okay but we need to
+ * adjust the MSS of the connection to take into
+ * account any labeling overhead, since we don't know
+ * the exact overhead at this point we'll use the worst
+ * case value which is 40 bytes for IPv4 */
+ struct inet_connection_sock *sk_conn = inet_csk(sk);
+ sk_conn->icsk_ext_hdr_len += 40 -
+ (sk_inet->opt ? sk_inet->opt->optlen : 0);
+ sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+
+ sksec->nlbl_state = NLBL_REQSKB;
+ } else
+ sksec->nlbl_state = NLBL_CONNLABELED;
+ break;
+ default:
+ /* note that we are failing to label the socket which could be
+ * a bad thing since it means traffic could leave the system
+ * without the desired labeling, however, all is not lost as
+ * we have a check in selinux_netlbl_inode_permission() to
+ * pick up the pieces that we might drop here because we can't
+ * return an error code */
+ break;
+ }
}
/**
@@ -205,13 +361,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
*/
int selinux_netlbl_socket_post_create(struct socket *sock)
{
- struct sock *sk = sock->sk;
- struct sk_security_struct *sksec = sk->sk_security;
-
- if (sksec->nlbl_state != NLBL_REQUIRE)
- return 0;
-
- return selinux_netlbl_sock_setsid(sk, sksec->sid);
+ return selinux_netlbl_sock_setsid(sock->sk);
}
/**
@@ -246,7 +396,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
local_bh_disable();
bh_lock_sock_nested(sk);
if (likely(sksec->nlbl_state == NLBL_REQUIRE))
- rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
+ rc = selinux_netlbl_sock_setsid(sk);
else
rc = 0;
bh_unlock_sock(sk);
@@ -307,7 +457,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
return 0;
if (nlbl_sid != SECINITSID_UNLABELED)
- netlbl_skbuff_err(skb, rc);
+ netlbl_skbuff_err(skb, rc, 0);
return rc;
}
@@ -334,7 +484,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
struct netlbl_lsm_secattr secattr;
if (level == IPPROTO_IP && optname == IP_OPTIONS &&
- sksec->nlbl_state == NLBL_LABELED) {
+ (sksec->nlbl_state == NLBL_LABELED ||
+ sksec->nlbl_state == NLBL_CONNLABELED)) {
netlbl_secattr_init(&secattr);
lock_sock(sk);
rc = netlbl_sock_getattr(sk, &secattr);
@@ -346,3 +497,50 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
return rc;
}
+
+/**
+ * selinux_netlbl_socket_connect - Label a client-side socket on connect
+ * @sk: the socket to label
+ * @addr: the destination address
+ *
+ * Description:
+ * Attempt to label a connected socket with NetLabel using the given address.
+ * Returns zero values on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
+{
+ int rc;
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct netlbl_lsm_secattr *secattr;
+
+ if (sksec->nlbl_state != NLBL_REQSKB &&
+ sksec->nlbl_state != NLBL_CONNLABELED)
+ return 0;
+
+ local_bh_disable();
+ bh_lock_sock_nested(sk);
+
+ /* connected sockets are allowed to disconnect when the address family
+ * is set to AF_UNSPEC, if that is what is happening we want to reset
+ * the socket */
+ if (addr->sa_family == AF_UNSPEC) {
+ netlbl_sock_delattr(sk);
+ sksec->nlbl_state = NLBL_REQSKB;
+ rc = 0;
+ goto socket_connect_return;
+ }
+ secattr = selinux_netlbl_sock_genattr(sk);
+ if (secattr == NULL) {
+ rc = -ENOMEM;
+ goto socket_connect_return;
+ }
+ rc = netlbl_conn_setattr(sk, addr, secattr);
+ if (rc == 0)
+ sksec->nlbl_state = NLBL_CONNLABELED;
+
+socket_connect_return:
+ bh_unlock_sock(sk);
+ local_bh_enable();
+ return rc;
+}
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index ab0cc0c7b94..343c8ab14af 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2955,7 +2955,7 @@ netlbl_secattr_to_sid_return_cleanup:
*/
int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
{
- int rc = -ENOENT;
+ int rc;
struct context *ctx;
if (!ss_initialized)
@@ -2963,11 +2963,18 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
read_lock(&policy_rwlock);
ctx = sidtab_search(&sidtab, sid);
- if (ctx == NULL)
+ if (ctx == NULL) {
+ rc = -ENOENT;
goto netlbl_sid_to_secattr_failure;
+ }
secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
GFP_ATOMIC);
- secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY;
+ if (secattr->domain == NULL) {
+ rc = -ENOMEM;
+ goto netlbl_sid_to_secattr_failure;
+ }
+ secattr->attr.secid = sid;
+ secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
mls_export_netlbl_lvl(ctx, secattr);
rc = mls_export_netlbl_cat(ctx, secattr);
if (rc != 0)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 87d75417ea9..6e2dc0bab70 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2179,7 +2179,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* This is the simplist possible security model
* for networking.
*/
- return smk_access(smack, ssp->smk_in, MAY_WRITE);
+ rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+ if (rc != 0)
+ netlbl_skbuff_err(skb, rc, 0);
+ return rc;
}
/**
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index e7c642458ec..c21d8c8bf0c 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -354,9 +354,11 @@ static void smk_cipso_doi(void)
doip->tags[rc] = CIPSO_V4_TAG_INVALID;
rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
- if (rc != 0)
+ if (rc != 0) {
printk(KERN_WARNING "%s:%d add rc = %d\n",
__func__, __LINE__, rc);
+ kfree(doip);
+ }
}
/**
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index a7b46ec72f3..1b3534d6768 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -33,9 +33,6 @@
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <sound/memalloc.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
@@ -162,39 +159,6 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
}
#endif /* CONFIG_HAS_DMA */
-#ifdef CONFIG_SBUS
-
-static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
- dma_addr_t *dma_addr)
-{
- struct sbus_dev *sdev = (struct sbus_dev *)dev;
- int pg;
- void *res;
-
- if (WARN_ON(!dma_addr))
- return NULL;
- pg = get_order(size);
- res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
- if (res != NULL)
- inc_snd_pages(pg);
- return res;
-}
-
-static void snd_free_sbus_pages(struct device *dev, size_t size,
- void *ptr, dma_addr_t dma_addr)
-{
- struct sbus_dev *sdev = (struct sbus_dev *)dev;
- int pg;
-
- if (ptr == NULL)
- return;
- pg = get_order(size);
- dec_snd_pages(pg);
- sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-}
-
-#endif /* CONFIG_SBUS */
-
/*
*
* ALSA generic memory management
@@ -231,11 +195,6 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->area = snd_malloc_pages(size, (unsigned long)device);
dmab->addr = 0;
break;
-#ifdef CONFIG_SBUS
- case SNDRV_DMA_TYPE_SBUS:
- dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr);
- break;
-#endif
#ifdef CONFIG_HAS_DMA
case SNDRV_DMA_TYPE_DEV:
dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
@@ -306,11 +265,6 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
case SNDRV_DMA_TYPE_CONTINUOUS:
snd_free_pages(dmab->area, dmab->bytes);
break;
-#ifdef CONFIG_SBUS
- case SNDRV_DMA_TYPE_SBUS:
- snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
- break;
-#endif
#ifdef CONFIG_HAS_DMA
case SNDRV_DMA_TYPE_DEV:
snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
@@ -419,7 +373,7 @@ static int snd_mem_proc_read(struct seq_file *seq, void *offset)
long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
struct snd_mem_list *mem;
int devno;
- static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
+ static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
mutex_lock(&list_mutex);
seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n",
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index b63839e8f9b..456a1b4d783 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -30,7 +30,7 @@
**************************************************************************
*
* History
- * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
* Removed non existant WM9700
* Added support for WM9705, WM9708, WM9709, WM9710, WM9711
* WM9712 and WM9717
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 6ce3cbe98a6..6e831aff1bd 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -476,7 +476,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97)
}
/*
- * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
* removed broken wolfson00 patch.
* added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
*/
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index c461baa83c2..c5906551311 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -322,8 +322,8 @@ static hda_nid_t stac92hd71bxx_mux_nids[2] = {
0x1a, 0x1b
};
-static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
- 0x1c,
+static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
+ 0x1c, 0x1d,
};
static hda_nid_t stac92hd71bxx_smux_nids[2] = {
@@ -861,20 +861,18 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
/* connect headphone jack to dac1 */
{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
};
-#define HD_DISABLE_PORTF 3
+#define HD_DISABLE_PORTF 2
static struct hda_verb stac92hd71bxx_analog_core_init[] = {
/* start of config #1 */
/* connect port 0f to audio mixer */
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
/* unmute right and left channels for node 0x0f */
{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* start of config #2 */
@@ -883,10 +881,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
/* connect headphone jack to dac1 */
{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* connect port 0d to audio mixer */
- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
- /* unmute dac0 input in audio mixer */
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
/* unmute right and left channels for nodes 0x0a, 0xd */
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1107,6 +1101,7 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
STAC_INPUT_SOURCE(2),
+ STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
@@ -1119,8 +1114,17 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
*/
- HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
- HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
+ HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
+
+ HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
+
+ HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
+ HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
+
+ HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
+ HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
{ } /* end */
};
@@ -1649,7 +1653,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
static unsigned int ref92hd71bxx_pin_configs[11] = {
0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
- 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
+ 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
0x90a000f0, 0x01452050, 0x01452050,
};
@@ -3000,7 +3004,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
/* labels for amp mux outputs */
static const char *stac92xx_amp_labels[3] = {
- "Front Microphone", "Microphone", "Line In"
+ "Front Microphone", "Microphone", "Line In",
};
/* create amp out controls mux on capable codecs */
@@ -4327,6 +4331,16 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = {
#endif
};
+static struct hda_input_mux stac92hd71bxx_dmux = {
+ .num_items = 4,
+ .items = {
+ { "Analog Inputs", 0x00 },
+ { "Mixer", 0x01 },
+ { "Digital Mic 1", 0x02 },
+ { "Digital Mic 2", 0x03 },
+ }
+};
+
static int patch_stac92hd71bxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -4341,6 +4355,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
spec->pin_nids = stac92hd71bxx_pin_nids;
+ memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
+ sizeof(stac92hd71bxx_dmux));
spec->board_config = snd_hda_check_board_config(codec,
STAC_92HD71BXX_MODELS,
stac92hd71bxx_models,
@@ -4392,6 +4408,7 @@ again:
/* no output amps */
spec->num_pwrs = 0;
spec->mixer = stac92hd71bxx_analog_mixer;
+ spec->dinput_mux = &spec->private_dimux;
/* disable VSW */
spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
@@ -4409,12 +4426,13 @@ again:
spec->num_pwrs = 0;
/* fallthru */
default:
+ spec->dinput_mux = &spec->private_dimux;
spec->mixer = stac92hd71bxx_analog_mixer;
spec->init = stac92hd71bxx_analog_core_init;
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
}
- spec->aloopback_mask = 0x20;
+ spec->aloopback_mask = 0x50;
spec->aloopback_shift = 0;
if (spec->board_config > STAC_92HD71BXX_REF) {
@@ -4456,6 +4474,10 @@ again:
spec->multiout.num_dacs = 1;
spec->multiout.hp_nid = 0x11;
spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+ if (spec->dinput_mux)
+ spec->private_dimux.num_items +=
+ spec->num_dmics -
+ (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
if (!err) {
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
index 905186502e0..85a883299c2 100644
--- a/sound/soc/at91/Kconfig
+++ b/sound/soc/at91/Kconfig
@@ -8,20 +8,3 @@ config SND_AT91_SOC
config SND_AT91_SOC_SSC
tristate
-
-config SND_AT91_SOC_ETI_B1_WM8731
- tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards"
- depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
- select SND_AT91_SOC_SSC
- select SND_SOC_WM8731
- help
- Say Y if you want to add support for SoC audio on WM8731-based
- Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
-
-config SND_AT91_SOC_ETI_SLAVE
- bool "Run codec in slave Mode on Endrelia boards"
- depends on SND_AT91_SOC_ETI_B1_WM8731
- default n
- help
- Say Y if you want to run with the AT91 SSC generating the BCLK
- and LRC signals on Endrelia boards.
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
index f23da17cc32..b817f11df28 100644
--- a/sound/soc/at91/Makefile
+++ b/sound/soc/at91/Makefile
@@ -4,8 +4,3 @@ snd-soc-at91-ssc-objs := at91-ssc.o
obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
-
-# AT91 Machine Support
-snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
-
-obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c
index a5b1a79ebff..1b61cc46126 100644
--- a/sound/soc/at91/at91-ssc.c
+++ b/sound/soc/at91/at91-ssc.c
@@ -5,7 +5,7 @@
* Endrelia Technologies Inc.
*
* Based on pxa2xx Platform drivers by
- * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
deleted file mode 100644
index 684781e4088..00000000000
--- a/sound/soc/at91/eti_b1_wm8731.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
- *
- * Author: Frank Mandarino <fmandarino@endrelia.com>
- * Endrelia Technologies Inc.
- * Created: Mar 29, 2006
- *
- * Based on corgi.c by:
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- *
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
- * 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 as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-
-#include "../codecs/wm8731.h"
-#include "at91-pcm.h"
-#include "at91-ssc.h"
-
-#if 0
-#define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x)
-#else
-#define DBG(x...)
-#endif
-
-static struct clk *pck1_clk;
-static struct clk *pllb_clk;
-
-
-static int eti_b1_startup(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- int ret;
-
- /* cpu clock is the AT91 master clock sent to the SSC */
- ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
- 60000000, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* codec system clock is supplied by PCK1, set to 12MHz */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
- 12000000, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* Start PCK1 clock. */
- clk_enable(pck1_clk);
- DBG("pck1 started\n");
-
- return 0;
-}
-
-static void eti_b1_shutdown(struct snd_pcm_substream *substream)
-{
- /* Stop PCK1 clock. */
- clk_disable(pck1_clk);
- DBG("pck1 stopped\n");
-}
-
-static int eti_b1_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- int ret;
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
- unsigned int rate;
- int cmr_div, period;
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /*
- * The SSC clock dividers depend on the sample rate. The CMR.DIV
- * field divides the system master clock MCK to drive the SSC TK
- * signal which provides the codec BCLK. The TCMR.PERIOD and
- * RCMR.PERIOD fields further divide the BCLK signal to drive
- * the SSC TF and RF signals which provide the codec DACLRC and
- * ADCLRC clocks.
- *
- * The dividers were determined through trial and error, where a
- * CMR.DIV value is chosen such that the resulting BCLK value is
- * divisible, or almost divisible, by (2 * sample rate), and then
- * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
- */
- rate = params_rate(params);
-
- switch (rate) {
- case 8000:
- cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */
- period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */
- break;
- case 32000:
- cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
- period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
- break;
- case 48000:
- cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
- period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
- break;
- default:
- printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
- return -EINVAL;
- }
-
- /* set the MCK divider for BCLK */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
- if (ret < 0)
- return ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* set the BCLK divider for DACLRC */
- ret = snd_soc_dai_set_clkdiv(cpu_dai,
- AT91SSC_TCMR_PERIOD, period);
- } else {
- /* set the BCLK divider for ADCLRC */
- ret = snd_soc_dai_set_clkdiv(cpu_dai,
- AT91SSC_RCMR_PERIOD, period);
- }
- if (ret < 0)
- return ret;
-
-#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
- /*
- * Codec in Master Mode.
- */
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
-#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
-
- return 0;
-}
-
-static struct snd_soc_ops eti_b1_ops = {
- .startup = eti_b1_startup,
- .hw_params = eti_b1_hw_params,
- .shutdown = eti_b1_shutdown,
-};
-
-
-static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("Int Mic", NULL),
- SND_SOC_DAPM_SPK("Ext Spk", NULL),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-
- /* speaker connected to LHPOUT */
- {"Ext Spk", NULL, "LHPOUT"},
-
- /* mic is connected to Mic Jack, with WM8731 Mic Bias */
- {"MICIN", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Int Mic"},
-};
-
-/*
- * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
- */
-static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
-{
- DBG("eti_b1_wm8731_init() called\n");
-
- /* Add specific widgets */
- snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets,
- ARRAY_SIZE(eti_b1_dapm_widgets));
-
- /* Set up specific audio path interconnects */
- snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon));
-
- /* not connected */
- snd_soc_dapm_disable_pin(codec, "RLINEIN");
- snd_soc_dapm_disable_pin(codec, "LLINEIN");
-
- /* always connected */
- snd_soc_dapm_enable_pin(codec, "Int Mic");
- snd_soc_dapm_enable_pin(codec, "Ext Spk");
-
- snd_soc_dapm_sync(codec);
-
- return 0;
-}
-
-static struct snd_soc_dai_link eti_b1_dai = {
- .name = "WM8731",
- .stream_name = "WM8731 PCM",
- .cpu_dai = &at91_ssc_dai[1],
- .codec_dai = &wm8731_dai,
- .init = eti_b1_wm8731_init,
- .ops = &eti_b1_ops,
-};
-
-static struct snd_soc_machine snd_soc_machine_eti_b1 = {
- .name = "ETI_B1_WM8731",
- .dai_link = &eti_b1_dai,
- .num_links = 1,
-};
-
-static struct wm8731_setup_data eti_b1_wm8731_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1a,
-};
-
-static struct snd_soc_device eti_b1_snd_devdata = {
- .machine = &snd_soc_machine_eti_b1,
- .platform = &at91_soc_platform,
- .codec_dev = &soc_codec_dev_wm8731,
- .codec_data = &eti_b1_wm8731_setup,
-};
-
-static struct platform_device *eti_b1_snd_device;
-
-static int __init eti_b1_init(void)
-{
- int ret;
- struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
- if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
- DBG("SSC1 memory region is busy\n");
- return -EBUSY;
- }
-
- ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
- if (!ssc->base) {
- DBG("SSC1 memory ioremap failed\n");
- ret = -ENOMEM;
- goto fail_release_mem;
- }
-
- ssc->pid = AT91RM9200_ID_SSC1;
-
- eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
- if (!eti_b1_snd_device) {
- DBG("platform device allocation failed\n");
- ret = -ENOMEM;
- goto fail_io_unmap;
- }
-
- platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
- eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
-
- ret = platform_device_add(eti_b1_snd_device);
- if (ret) {
- DBG("platform device add failed\n");
- platform_device_put(eti_b1_snd_device);
- goto fail_io_unmap;
- }
-
- at91_set_A_periph(AT91_PIN_PB6, 0); /* TF1 */
- at91_set_A_periph(AT91_PIN_PB7, 0); /* TK1 */
- at91_set_A_periph(AT91_PIN_PB8, 0); /* TD1 */
- at91_set_A_periph(AT91_PIN_PB9, 0); /* RD1 */
-/* at91_set_A_periph(AT91_PIN_PB10, 0);*/ /* RK1 */
- at91_set_A_periph(AT91_PIN_PB11, 0); /* RF1 */
-
- /*
- * Set PCK1 parent to PLLB and its rate to 12 Mhz.
- */
- pllb_clk = clk_get(NULL, "pllb");
- pck1_clk = clk_get(NULL, "pck1");
-
- clk_set_parent(pck1_clk, pllb_clk);
- clk_set_rate(pck1_clk, 12000000);
-
- DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
-
- /* assign the GPIO pin to PCK1 */
- at91_set_B_periph(AT91_PIN_PA24, 0);
-
-#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
- printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
-#else
- printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
-#endif
- return ret;
-
-fail_io_unmap:
- iounmap(ssc->base);
-fail_release_mem:
- release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
- return ret;
-}
-
-static void __exit eti_b1_exit(void)
-{
- struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
-
- clk_put(pck1_clk);
- clk_put(pllb_clk);
-
- platform_device_unregister(eti_b1_snd_device);
-
- iounmap(ssc->base);
- release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
-}
-
-module_init(eti_b1_init);
-module_exit(eti_b1_exit);
-
-/* Module information */
-MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
-MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index f98331d099e..dc006206f62 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -17,6 +17,22 @@ config SND_BF5XX_SOC_SSM2602
help
Say Y if you want to add support for SoC audio on BF527-EZKIT.
+config SND_BF5XX_SOC_AD73311
+ tristate "SoC AD73311 Audio support for Blackfin"
+ depends on SND_BF5XX_I2S
+ select SND_BF5XX_SOC_I2S
+ select SND_SOC_AD73311
+ help
+ Say Y if you want to add support for AD73311 codec on Blackfin.
+
+config SND_BFIN_AD73311_SE
+ int "PF pin for AD73311L Chip Select"
+ depends on SND_BF5XX_SOC_AD73311
+ default 4
+ help
+ Enter the GPIO used to control AD73311's SE pin. Acceptable
+ values are 0 to 7
+
config SND_BF5XX_AC97
tristate "SoC AC97 Audio for the ADI BF5xx chip"
depends on BLACKFIN && SND_SOC
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 9ea8bd9e0ba..97bb37a6359 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -14,7 +14,8 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
# Blackfin Machine Support
snd-ad1980-objs := bf5xx-ad1980.o
snd-ssm2602-objs := bf5xx-ssm2602.o
-
+snd-ad73311-objs := bf5xx-ad73311.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
+obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 51f4907c483..25e50d2ea1e 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -56,6 +56,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
sport->tx_pos += runtime->period_size;
if (sport->tx_pos >= runtime->buffer_size)
sport->tx_pos %= runtime->buffer_size;
+ sport->tx_delay_pos = sport->tx_pos;
} else {
bf5xx_ac97_to_pcm(
(struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
@@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data)
struct snd_pcm_substream *pcm = data;
#if defined(CONFIG_SND_MMAP_SUPPORT)
struct snd_pcm_runtime *runtime = pcm->runtime;
+ struct sport_device *sport = runtime->private_data;
bf5xx_mmap_copy(pcm, runtime->period_size);
+ if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (sport->once == 0) {
+ snd_pcm_period_elapsed(pcm);
+ bf5xx_mmap_copy(pcm, runtime->period_size);
+ sport->once = 1;
+ }
+ }
#endif
snd_pcm_period_elapsed(pcm);
}
@@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ memset(runtime->dma_area, 0, runtime->buffer_size);
snd_pcm_lib_free_pages(substream);
return 0;
}
@@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
* SPORT working in TMD mode(include AC97).
*/
#if defined(CONFIG_SND_MMAP_SUPPORT)
- size_t size = bf5xx_pcm_hardware.buffer_bytes_max
- * sizeof(struct ac97_frame) / 4;
- /*clean up intermediate buffer*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- memset(sport->tx_dma_buf, 0, size);
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
} else {
- memset(sport->rx_dma_buf, 0, size);
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
@@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
pr_debug("%s enter\n", __func__);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ bf5xx_mmap_copy(substream, runtime->period_size);
+ snd_pcm_period_elapsed(substream);
+ sport->tx_delay_pos = 0;
sport_tx_start(sport);
+ }
else
sport_rx_start(sport);
break;
@@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
#if defined(CONFIG_SND_MMAP_SUPPORT)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- curr = sport->tx_pos;
+ curr = sport->tx_delay_pos;
else
curr = sport->rx_pos;
#else
@@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
return ret;
}
+static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct sport_device *sport = runtime->private_data;
+
+ pr_debug("%s enter\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ sport->once = 0;
+ memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+ } else
+ memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
+
+ return 0;
+}
+
#ifdef CONFIG_SND_MMAP_SUPPORT
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
@@ -272,6 +299,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
.open = bf5xx_pcm_open,
+ .close = bf5xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
.hw_free = bf5xx_pcm_hw_free,
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index c782e311fd5..5e5aafb6485 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -129,7 +129,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
struct ac97_frame *nextwrite;
sport_incfrag(sport, &nextfrag, 1);
- sport_incfrag(sport, &nextfrag, 1);
nextwrite = (struct ac97_frame *)(sport->tx_buf + \
nextfrag * sport->tx_fragsize);
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
new file mode 100644
index 00000000000..622c9b90953
--- /dev/null
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -0,0 +1,240 @@
+/*
+ * File: sound/soc/blackfin/bf5xx-ad73311.c
+ * Author: Cliff Cai <Cliff.Cai@analog.com>
+ *
+ * Created: Thur Sep 25 2008
+ * Description: Board driver for ad73311 sound chip
+ *
+ * Modified:
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include "../codecs/ad73311.h"
+#include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
+#include "bf5xx-i2s.h"
+
+#if CONFIG_SND_BF5XX_SPORT_NUM == 0
+#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
+#define bfin_read_SPORT_TCR1 bfin_read_SPORT0_TCR1
+#define bfin_write_SPORT_TCR2 bfin_write_SPORT0_TCR2
+#define bfin_write_SPORT_TX16 bfin_write_SPORT0_TX16
+#define bfin_read_SPORT_STAT bfin_read_SPORT0_STAT
+#else
+#define bfin_write_SPORT_TCR1 bfin_write_SPORT1_TCR1
+#define bfin_read_SPORT_TCR1 bfin_read_SPORT1_TCR1
+#define bfin_write_SPORT_TCR2 bfin_write_SPORT1_TCR2
+#define bfin_write_SPORT_TX16 bfin_write_SPORT1_TX16
+#define bfin_read_SPORT_STAT bfin_read_SPORT1_STAT
+#endif
+
+#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
+
+static struct snd_soc_machine bf5xx_ad73311;
+
+static int snd_ad73311_startup(void)
+{
+ pr_debug("%s enter\n", __func__);
+
+ /* Pull up SE pin on AD73311L */
+ gpio_set_value(GPIO_SE, 1);
+ return 0;
+}
+
+static int snd_ad73311_configure(void)
+{
+ unsigned short ctrl_regs[6];
+ unsigned short status = 0;
+ int count = 0;
+
+ /* DMCLK = MCLK = 16.384 MHz
+ * SCLK = DMCLK/8 = 2.048 MHz
+ * Sample Rate = DMCLK/2048 = 8 KHz
+ */
+ ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
+ REGB_SCDIV(0) | REGB_DIRATE(0);
+ ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
+ REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
+ ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
+ REGD_IGS(2);
+ ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
+ ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
+ ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
+
+ local_irq_disable();
+ snd_ad73311_startup();
+ udelay(1);
+
+ bfin_write_SPORT_TCR1(TFSR);
+ bfin_write_SPORT_TCR2(0xF);
+ SSYNC();
+
+ /* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
+ * FIFO before enable SPORT to transfer the data
+ */
+ for (count = 0; count < 6; count++)
+ bfin_write_SPORT_TX16(ctrl_regs[count]);
+ SSYNC();
+ bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
+ SSYNC();
+
+ /* When TUVF is set, the data is already send out */
+ while (!(status & TUVF) && count++ < 10000) {
+ udelay(1);
+ status = bfin_read_SPORT_STAT();
+ SSYNC();
+ }
+ bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
+ SSYNC();
+ local_irq_enable();
+
+ if (count == 10000) {
+ printk(KERN_ERR "ad73311: failed to configure codec\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int bf5xx_probe(struct platform_device *pdev)
+{
+ int err;
+ if (gpio_request(GPIO_SE, "AD73311_SE")) {
+ printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
+ return -EBUSY;
+ }
+
+ gpio_direction_output(GPIO_SE, 0);
+
+ err = snd_ad73311_configure();
+ if (err < 0)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ pr_debug("%s enter\n", __func__);
+ cpu_dai->private_data = sport_handle;
+ return 0;
+}
+
+static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
+ params_format(params));
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+
+static struct snd_soc_ops bf5xx_ad73311_ops = {
+ .startup = bf5xx_ad73311_startup,
+ .hw_params = bf5xx_ad73311_hw_params,
+};
+
+static struct snd_soc_dai_link bf5xx_ad73311_dai = {
+ .name = "ad73311",
+ .stream_name = "AD73311",
+ .cpu_dai = &bf5xx_i2s_dai,
+ .codec_dai = &ad73311_dai,
+ .ops = &bf5xx_ad73311_ops,
+};
+
+static struct snd_soc_machine bf5xx_ad73311 = {
+ .name = "bf5xx_ad73311",
+ .probe = bf5xx_probe,
+ .dai_link = &bf5xx_ad73311_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
+ .machine = &bf5xx_ad73311,
+ .platform = &bf5xx_i2s_soc_platform,
+ .codec_dev = &soc_codec_dev_ad73311,
+};
+
+static struct platform_device *bf52x_ad73311_snd_device;
+
+static int __init bf5xx_ad73311_init(void)
+{
+ int ret;
+
+ pr_debug("%s enter\n", __func__);
+ bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!bf52x_ad73311_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
+ bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
+ ret = platform_device_add(bf52x_ad73311_snd_device);
+
+ if (ret)
+ platform_device_put(bf52x_ad73311_snd_device);
+
+ return ret;
+}
+
+static void __exit bf5xx_ad73311_exit(void)
+{
+ pr_debug("%s enter\n", __func__);
+ platform_device_unregister(bf52x_ad73311_snd_device);
+}
+
+module_init(bf5xx_ad73311_init);
+module_exit(bf5xx_ad73311_exit);
+
+/* Module information */
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index 43a4092eeb8..827587f0818 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -70,6 +70,13 @@ static struct sport_param sport_params[2] = {
}
};
+static u16 sport_req[][7] = {
+ { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+ P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
+ { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+ P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
+};
+
static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
@@ -78,6 +85,14 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
/* interface format:support I2S,slave mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
+ bf5xx_i2s.tcr1 |= TFSR | TCKFE;
+ bf5xx_i2s.rcr1 |= RFSR | RCKFE;
+ bf5xx_i2s.tcr2 |= TSFSE;
+ bf5xx_i2s.rcr2 |= RSFSE;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ bf5xx_i2s.tcr1 |= TFSR;
+ bf5xx_i2s.rcr1 |= RFSR;
break;
case SND_SOC_DAIFMT_LEFT_J:
ret = -EINVAL;
@@ -127,14 +142,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S16_LE:
bf5xx_i2s.tcr2 |= 15;
bf5xx_i2s.rcr2 |= 15;
+ sport_handle->wdsize = 2;
break;
case SNDRV_PCM_FORMAT_S24_LE:
bf5xx_i2s.tcr2 |= 23;
bf5xx_i2s.rcr2 |= 23;
+ sport_handle->wdsize = 3;
break;
case SNDRV_PCM_FORMAT_S32_LE:
bf5xx_i2s.tcr2 |= 31;
bf5xx_i2s.rcr2 |= 31;
+ sport_handle->wdsize = 4;
break;
}
@@ -145,17 +163,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
* need to configure both of them at the time when the first
* stream is opened.
*
- * CPU DAI format:I2S, slave mode.
+ * CPU DAI:slave mode.
*/
- ret = sport_config_rx(sport_handle, RFSR | RCKFE,
- RSFSE|bf5xx_i2s.rcr2, 0, 0);
+ ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
+ bf5xx_i2s.rcr2, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
- ret = sport_config_tx(sport_handle, TFSR | TCKFE,
- TSFSE|bf5xx_i2s.tcr2, 0, 0);
+ ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
+ bf5xx_i2s.tcr2, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
@@ -174,13 +192,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
static int bf5xx_i2s_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
- u16 sport_req[][7] = {
- { P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
- P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
- { P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
- P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
- };
-
pr_debug("%s enter\n", __func__);
if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
pr_err("Requesting Peripherals failed\n");
@@ -198,6 +209,13 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
return 0;
}
+static void bf5xx_i2s_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ pr_debug("%s enter\n", __func__);
+ peripheral_free_list(&sport_req[sport_num][0]);
+}
+
#ifdef CONFIG_PM
static int bf5xx_i2s_suspend(struct platform_device *dev,
struct snd_soc_dai *dai)
@@ -263,15 +281,16 @@ struct snd_soc_dai bf5xx_i2s_dai = {
.id = 0,
.type = SND_SOC_DAI_I2S,
.probe = bf5xx_i2s_probe,
+ .remove = bf5xx_i2s_remove,
.suspend = bf5xx_i2s_suspend,
.resume = bf5xx_i2s_resume,
.playback = {
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
.capture = {
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
index 4c163454bbf..fcadcc081f7 100644
--- a/sound/soc/blackfin/bf5xx-sport.h
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -123,6 +123,8 @@ struct sport_device {
int rx_pos;
unsigned int tx_buffer_size;
unsigned int rx_buffer_size;
+ int tx_delay_pos;
+ int once;
#endif
void *private_data;
};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e0b9869df0f..4975d8573e4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -3,9 +3,11 @@ config SND_SOC_ALL_CODECS
depends on I2C
select SPI
select SPI_MASTER
+ select SND_SOC_AD73311
select SND_SOC_AK4535
select SND_SOC_CS4270
select SND_SOC_SSM2602
+ select SND_SOC_TLV320AIC23
select SND_SOC_TLV320AIC26
select SND_SOC_TLV320AIC3X
select SND_SOC_UDA1380
@@ -34,6 +36,9 @@ config SND_SOC_AC97_CODEC
config SND_SOC_AD1980
tristate
+config SND_SOC_AD73311
+ tristate
+
config SND_SOC_AK4535
tristate
@@ -58,9 +63,13 @@ config SND_SOC_CS4270_VD33_ERRATA
config SND_SOC_SSM2602
tristate
+config SND_SOC_TLV320AIC23
+ tristate
+ depends on I2C
+
config SND_SOC_TLV320AIC26
tristate "TI TLV320AIC26 Codec support"
- depends on SND_SOC && SPI
+ depends on SPI
config SND_SOC_TLV320AIC3X
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f977978a340..90f0a585fc7 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,8 +1,10 @@
snd-soc-ac97-objs := ac97.o
snd-soc-ad1980-objs := ad1980.o
+snd-soc-ad73311-objs := ad73311.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-ssm2602-objs := ssm2602.o
+snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-uda1380-objs := uda1380.o
@@ -20,9 +22,11 @@ snd-soc-wm9713-objs := wm9713.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
+obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
+obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 61fd96ca7bc..bd1ebdc6c86 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -2,8 +2,7 @@
* ac97.c -- ALSA Soc AC97 codec support
*
* Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 4e09c1f2c06..1397b8e06c0 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/core.h>
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
new file mode 100644
index 00000000000..37af8607b00
--- /dev/null
+++ b/sound/soc/codecs/ad73311.c
@@ -0,0 +1,107 @@
+/*
+ * ad73311.c -- ALSA Soc AD73311 codec support
+ *
+ * Copyright: Analog Device Inc.
+ * Author: Cliff Cai <cliff.cai@analog.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Revision history
+ * 25th Sep 2008 Initial version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "ad73311.h"
+
+struct snd_soc_dai ad73311_dai = {
+ .name = "AD73311",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+EXPORT_SYMBOL_GPL(ad73311_dai);
+
+static int ad73311_soc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+ mutex_init(&codec->mutex);
+ codec->name = "AD73311";
+ codec->owner = THIS_MODULE;
+ codec->dai = &ad73311_dai;
+ codec->num_dai = 1;
+ socdev->codec = codec;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "ad73311: failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "ad73311: failed to register card\n");
+ goto register_err;
+ }
+
+ return ret;
+
+register_err:
+ snd_soc_free_pcms(socdev);
+pcm_err:
+ kfree(socdev->codec);
+ socdev->codec = NULL;
+ return ret;
+}
+
+static int ad73311_soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ if (codec == NULL)
+ return 0;
+ snd_soc_free_pcms(socdev);
+ kfree(codec);
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ad73311 = {
+ .probe = ad73311_soc_probe,
+ .remove = ad73311_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
+
+MODULE_DESCRIPTION("ASoC ad73311 driver");
+MODULE_AUTHOR("Cliff Cai ");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
new file mode 100644
index 00000000000..507ce0c30ed
--- /dev/null
+++ b/sound/soc/codecs/ad73311.h
@@ -0,0 +1,90 @@
+/*
+ * File: sound/soc/codec/ad73311.h
+ * Based on:
+ * Author: Cliff Cai <cliff.cai@analog.com>
+ *
+ * Created: Thur Sep 25, 2008
+ * Description: definitions for AD73311 registers
+ *
+ *
+ * Modified:
+ * Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __AD73311_H__
+#define __AD73311_H__
+
+#define AD_CONTROL 0x8000
+#define AD_DATA 0x0000
+#define AD_READ 0x4000
+#define AD_WRITE 0x0000
+
+/* Control register A */
+#define CTRL_REG_A (0 << 8)
+
+#define REGA_MODE_PRO 0x00
+#define REGA_MODE_DATA 0x01
+#define REGA_MODE_MIXED 0x03
+#define REGA_DLB 0x04
+#define REGA_SLB 0x08
+#define REGA_DEVC(x) ((x & 0x7) << 4)
+#define REGA_RESET 0x80
+
+/* Control register B */
+#define CTRL_REG_B (1 << 8)
+
+#define REGB_DIRATE(x) (x & 0x3)
+#define REGB_SCDIV(x) ((x & 0x3) << 2)
+#define REGB_MCDIV(x) ((x & 0x7) << 4)
+#define REGB_CEE (1 << 7)
+
+/* Control register C */
+#define CTRL_REG_C (2 << 8)
+
+#define REGC_PUDEV (1 << 0)
+#define REGC_PUADC (1 << 3)
+#define REGC_PUDAC (1 << 4)
+#define REGC_PUREF (1 << 5)
+#define REGC_REFUSE (1 << 6)
+
+/* Control register D */
+#define CTRL_REG_D (3 << 8)
+
+#define REGD_IGS(x) (x & 0x7)
+#define REGD_RMOD (1 << 3)
+#define REGD_OGS(x) ((x & 0x7) << 4)
+#define REGD_MUTE (x << 7)
+
+/* Control register E */
+#define CTRL_REG_E (4 << 8)
+
+#define REGE_DA(x) (x & 0x1f)
+#define REGE_IBYP (1 << 5)
+
+/* Control register F */
+#define CTRL_REG_F (5 << 8)
+
+#define REGF_SEEN (1 << 5)
+#define REGF_INV (1 << 6)
+#define REGF_ALB (1 << 7)
+
+extern struct snd_soc_dai ad73311_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ad73311;
+#endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 088cf992772..2a89b5888e1 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -28,7 +28,6 @@
#include "ak4535.h"
-#define AUDIO_NAME "ak4535"
#define AK4535_VERSION "0.3"
struct snd_soc_codec_device soc_codec_dev_ak4535;
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 940ce1c3522..44ef0dacd56 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -42,7 +42,6 @@
#include "ssm2602.h"
-#define AUDIO_NAME "ssm2602"
#define SSM2602_VERSION "0.1"
struct snd_soc_codec_device soc_codec_dev_ssm2602;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
new file mode 100644
index 00000000000..bac7815e00f
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -0,0 +1,714 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author: Arun KS, <arunks@mistralsolutions.com>
+ * Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
+ *
+ * Based on sound/soc/codecs/wm8731.c by 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.
+ *
+ * Notes:
+ * The AIC23 is a driver for a low power stereo audio
+ * codec tlv320aic23
+ *
+ * The machine layer should disable unsupported inputs/outputs by
+ * snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "tlv320aic23.h"
+
+#define AIC23_VERSION "0.1"
+
+struct tlv320aic23_srate_reg_info {
+ u32 sample_rate;
+ u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
+ u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+/*
+ * AIC23 register cache
+ */
+static const u16 tlv320aic23_reg[] = {
+ 0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */
+ 0x001A, 0x0004, 0x0007, 0x0001, /* 4 */
+ 0x0020, 0x0000, 0x0000, 0x0000, /* 8 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
+};
+
+/*
+ * read tlv320aic23 register cache
+ */
+static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
+ *codec, unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+ return -1;
+ return cache[reg];
+}
+
+/*
+ * write tlv320aic23 register cache
+ */
+static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
+ u8 reg, u16 value)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg >= ARRAY_SIZE(tlv320aic23_reg))
+ return;
+ cache[reg] = value;
+}
+
+/*
+ * write to the tlv320aic23 register space
+ */
+static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+
+ u8 data;
+
+ /* TLV320AIC23 has 7 bit address and 9 bits of data
+ * so we need to switch one data bit into reg and rest
+ * of data into val
+ */
+
+ if ((reg < 0 || reg > 9) && (reg != 15)) {
+ printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
+ return -1;
+ }
+
+ data = (reg << 1) | (value >> 8 & 0x01);
+
+ tlv320aic23_write_reg_cache(codec, reg, value);
+
+ if (codec->hw_write(codec->control_data, data,
+ (value & 0xff)) == 0)
+ return 0;
+
+ printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
+ value, reg);
+
+ return -EIO;
+}
+
+static const char *rec_src_text[] = { "Line", "Mic" };
+static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum rec_src_enum =
+ SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+
+static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
+SOC_DAPM_ENUM("Input Select", rec_src_enum);
+
+static const struct soc_enum tlv320aic23_rec_src =
+ SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
+static const struct soc_enum tlv320aic23_deemph =
+ SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
+static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
+
+static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u16 val, reg;
+
+ val = (ucontrol->value.integer.value[0] & 0x07);
+
+ /* linear conversion to userspace
+ * 000 = -6db
+ * 001 = -9db
+ * 010 = -12db
+ * 011 = -18db (Min)
+ * 100 = 0db (Max)
+ */
+ val = (val >= 4) ? 4 : (3 - val);
+
+ reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0);
+ tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
+
+ return 0;
+}
+
+static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u16 val;
+
+ val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0);
+ val = val >> 6;
+ val = (val >= 4) ? 4 : (3 - val);
+ ucontrol->value.integer.value[0] = val;
+ return 0;
+
+}
+
+#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
+ .put = snd_soc_tlv320aic23_put_volsw, \
+ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
+ TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
+ SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
+ SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
+ TLV320AIC23_RINVOL, 7, 1, 0),
+ SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
+ TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
+ SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
+ SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
+ SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG,
+ 6, 4, 0, sidetone_vol_tlv),
+ SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
+};
+
+/* add non dapm controls */
+static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
+{
+
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&tlv320aic23_snd_controls[i],
+ codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+
+}
+
+/* PGA Mixer controls for Line and Mic switch */
+static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
+ SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
+ SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
+ SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
+ SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+ &tlv320aic23_rec_src_mux_controls),
+ SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
+ &tlv320aic23_output_mixer_controls[0],
+ ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("LHPOUT"),
+ SND_SOC_DAPM_OUTPUT("RHPOUT"),
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
+
+ SND_SOC_DAPM_INPUT("LLINEIN"),
+ SND_SOC_DAPM_INPUT("RLINEIN"),
+
+ SND_SOC_DAPM_INPUT("MICIN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ /* Output Mixer */
+ {"Output Mixer", "Line Bypass Switch", "Line Input"},
+ {"Output Mixer", "Playback Switch", "DAC"},
+ {"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
+
+ /* Outputs */
+ {"RHPOUT", NULL, "Output Mixer"},
+ {"LHPOUT", NULL, "Output Mixer"},
+ {"LOUT", NULL, "Output Mixer"},
+ {"ROUT", NULL, "Output Mixer"},
+
+ /* Inputs */
+ {"Line Input", "NULL", "LLINEIN"},
+ {"Line Input", "NULL", "RLINEIN"},
+
+ {"Mic Input", "NULL", "MICIN"},
+
+ /* input mux */
+ {"Capture Source", "Line", "Line Input"},
+ {"Capture Source", "Mic", "Mic Input"},
+ {"ADC", NULL, "Capture Source"},
+
+};
+
+/* tlv320aic23 related */
+static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
+ {4000, 0x06, 1}, /* 4000 */
+ {8000, 0x06, 0}, /* 8000 */
+ {16000, 0x0C, 1}, /* 16000 */
+ {22050, 0x11, 1}, /* 22050 */
+ {24000, 0x00, 1}, /* 24000 */
+ {32000, 0x0C, 0}, /* 32000 */
+ {44100, 0x11, 0}, /* 44100 */
+ {48000, 0x00, 0}, /* 48000 */
+ {88200, 0x1F, 0}, /* 88200 */
+ {96000, 0x0E, 0}, /* 96000 */
+};
+
+static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+ ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+ /* set up audio path interconnects */
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ u16 iface_reg, data;
+ u8 count = 0;
+
+ iface_reg =
+ tlv320aic23_read_reg_cache(codec,
+ TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
+
+ /* Search for the right sample rate */
+ /* Verify what happens if the rate is not supported
+ * now it goes to 96Khz */
+ while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
+ (count < ARRAY_SIZE(srate_reg_info))) {
+ count++;
+ }
+
+ data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
+ (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
+ TLV320AIC23_USB_CLK_ON;
+
+ tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface_reg |= (0x01 << 2);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface_reg |= (0x02 << 2);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ iface_reg |= (0x03 << 2);
+ break;
+ }
+ tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+ return 0;
+}
+
+static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+
+ /* set active */
+ tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
+
+ return 0;
+}
+
+static void tlv320aic23_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+
+ /* deactivate */
+ if (!codec->active) {
+ udelay(50);
+ tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+ }
+}
+
+static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 reg;
+
+ reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT);
+ if (mute)
+ reg |= TLV320AIC23_DACM_MUTE;
+
+ else
+ reg &= ~TLV320AIC23_DACM_MUTE;
+
+ tlv320aic23_write(codec, TLV320AIC23_DIGT, reg);
+
+ return 0;
+}
+
+static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 iface_reg;
+
+ iface_reg =
+ tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface_reg |= TLV320AIC23_MS_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface_reg |= TLV320AIC23_FOR_I2S;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface_reg |= TLV320AIC23_FOR_DSP;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface_reg |= TLV320AIC23_FOR_LJUST;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+
+ tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
+
+ return 0;
+}
+
+static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ switch (freq) {
+ case 12000000:
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ /* vref/mid, osc on, dac unmute */
+ tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ /* everything off except vref/vmid, */
+ tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040);
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* everything off, dac mute, inactive */
+ tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+ tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define AIC23_RATES SNDRV_PCM_RATE_8000_96000
+#define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai tlv320aic23_dai = {
+ .name = "tlv320aic23",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AIC23_RATES,
+ .formats = AIC23_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AIC23_RATES,
+ .formats = AIC23_FORMATS,},
+ .ops = {
+ .prepare = tlv320aic23_pcm_prepare,
+ .hw_params = tlv320aic23_hw_params,
+ .shutdown = tlv320aic23_shutdown,
+ },
+ .dai_ops = {
+ .digital_mute = tlv320aic23_mute,
+ .set_fmt = tlv320aic23_set_dai_fmt,
+ .set_sysclk = tlv320aic23_set_dai_sysclk,
+ }
+};
+EXPORT_SYMBOL_GPL(tlv320aic23_dai);
+
+static int tlv320aic23_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
+ tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int tlv320aic23_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+ int i;
+ u16 reg;
+
+ /* Sync reg_cache with the hardware */
+ for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) {
+ u16 val = tlv320aic23_read_reg_cache(codec, reg);
+ tlv320aic23_write(codec, reg, val);
+ }
+
+ tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
+
+ return 0;
+}
+
+/*
+ * initialise the AIC23 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int tlv320aic23_init(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->codec;
+ int ret = 0;
+ u16 reg;
+
+ codec->name = "tlv320aic23";
+ codec->owner = THIS_MODULE;
+ codec->read = tlv320aic23_read_reg_cache;
+ codec->write = tlv320aic23_write;
+ codec->set_bias_level = tlv320aic23_set_bias_level;
+ codec->dai = &tlv320aic23_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
+ codec->reg_cache =
+ kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
+ if (codec->reg_cache == NULL)
+ return -ENOMEM;
+
+ /* Reset codec */
+ tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ /* power on device */
+ tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
+
+ /* Unmute input */
+ reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL);
+ tlv320aic23_write(codec, TLV320AIC23_LINVOL,
+ (reg & (~TLV320AIC23_LIM_MUTED)) |
+ (TLV320AIC23_LRS_ENABLED));
+
+ reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL);
+ tlv320aic23_write(codec, TLV320AIC23_RINVOL,
+ (reg & (~TLV320AIC23_LIM_MUTED)) |
+ TLV320AIC23_LRS_ENABLED);
+
+ reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG);
+ tlv320aic23_write(codec, TLV320AIC23_ANLG,
+ (reg) & (~TLV320AIC23_BYPASS_ON) &
+ (~TLV320AIC23_MICM_MUTED));
+
+ /* Default output volume */
+ tlv320aic23_write(codec, TLV320AIC23_LCHNVOL,
+ TLV320AIC23_DEFAULT_OUT_VOL &
+ TLV320AIC23_OUT_VOL_MASK);
+ tlv320aic23_write(codec, TLV320AIC23_RCHNVOL,
+ TLV320AIC23_DEFAULT_OUT_VOL &
+ TLV320AIC23_OUT_VOL_MASK);
+
+ tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
+
+ tlv320aic23_add_controls(codec);
+ tlv320aic23_add_widgets(codec);
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "tlv320aic23: failed to register card\n");
+ goto card_err;
+ }
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ kfree(codec->reg_cache);
+ return ret;
+}
+static struct snd_soc_device *tlv320aic23_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int tlv320aic23_codec_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *i2c_id)
+{
+ struct snd_soc_device *socdev = tlv320aic23_socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ int ret;
+
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EINVAL;
+
+ i2c_set_clientdata(i2c, codec);
+ codec->control_data = i2c;
+
+ ret = tlv320aic23_init(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
+ goto err;
+ }
+ return ret;
+
+err:
+ kfree(codec);
+ kfree(i2c);
+ return ret;
+}
+static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
+{
+ put_device(&i2c->dev);
+ return 0;
+}
+
+static const struct i2c_device_id tlv320aic23_id[] = {
+ {"tlv320aic23", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
+
+static struct i2c_driver tlv320aic23_i2c_driver = {
+ .driver = {
+ .name = "tlv320aic23",
+ },
+ .probe = tlv320aic23_codec_probe,
+ .remove = __exit_p(tlv320aic23_i2c_remove),
+ .id_table = tlv320aic23_id,
+};
+
+#endif
+
+static int tlv320aic23_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+
+ socdev->codec = codec;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ tlv320aic23_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data;
+ codec->hw_read = NULL;
+ ret = i2c_add_driver(&tlv320aic23_i2c_driver);
+ if (ret != 0)
+ printk(KERN_ERR "can't add i2c driver");
+#endif
+ return ret;
+}
+
+static int tlv320aic23_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
+
+ if (codec->control_data)
+ tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&tlv320aic23_i2c_driver);
+#endif
+ kfree(codec->reg_cache);
+ kfree(codec);
+
+ return 0;
+}
+struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
+ .probe = tlv320aic23_probe,
+ .remove = tlv320aic23_remove,
+ .suspend = tlv320aic23_suspend,
+ .resume = tlv320aic23_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h
new file mode 100644
index 00000000000..79d1faf8e57
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic23.h
@@ -0,0 +1,122 @@
+/*
+ * ALSA SoC TLV320AIC23 codec driver
+ *
+ * Author: Arun KS, <arunks@mistralsolutions.com>
+ * Copyright: (C) 2008 Mistral Solutions Pvt Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TLV320AIC23_H
+#define _TLV320AIC23_H
+
+/* Codec TLV320AIC23 */
+#define TLV320AIC23_LINVOL 0x00
+#define TLV320AIC23_RINVOL 0x01
+#define TLV320AIC23_LCHNVOL 0x02
+#define TLV320AIC23_RCHNVOL 0x03
+#define TLV320AIC23_ANLG 0x04
+#define TLV320AIC23_DIGT 0x05
+#define TLV320AIC23_PWR 0x06
+#define TLV320AIC23_DIGT_FMT 0x07
+#define TLV320AIC23_SRATE 0x08
+#define TLV320AIC23_ACTIVE 0x09
+#define TLV320AIC23_RESET 0x0F
+
+/* Left (right) line input volume control register */
+#define TLV320AIC23_LRS_ENABLED 0x0100
+#define TLV320AIC23_LIM_MUTED 0x0080
+#define TLV320AIC23_LIV_DEFAULT 0x0017
+#define TLV320AIC23_LIV_MAX 0x001f
+#define TLV320AIC23_LIV_MIN 0x0000
+
+/* Left (right) channel headphone volume control register */
+#define TLV320AIC23_LZC_ON 0x0080
+#define TLV320AIC23_LHV_DEFAULT 0x0079
+#define TLV320AIC23_LHV_MAX 0x007f
+#define TLV320AIC23_LHV_MIN 0x0000
+
+/* Analog audio path control register */
+#define TLV320AIC23_STA_REG(x) ((x)<<6)
+#define TLV320AIC23_STE_ENABLED 0x0020
+#define TLV320AIC23_DAC_SELECTED 0x0010
+#define TLV320AIC23_BYPASS_ON 0x0008
+#define TLV320AIC23_INSEL_MIC 0x0004
+#define TLV320AIC23_MICM_MUTED 0x0002
+#define TLV320AIC23_MICB_20DB 0x0001
+
+/* Digital audio path control register */
+#define TLV320AIC23_DACM_MUTE 0x0008
+#define TLV320AIC23_DEEMP_32K 0x0002
+#define TLV320AIC23_DEEMP_44K 0x0004
+#define TLV320AIC23_DEEMP_48K 0x0006
+#define TLV320AIC23_ADCHP_ON 0x0001
+
+/* Power control down register */
+#define TLV320AIC23_DEVICE_PWR_OFF 0x0080
+#define TLV320AIC23_CLK_OFF 0x0040
+#define TLV320AIC23_OSC_OFF 0x0020
+#define TLV320AIC23_OUT_OFF 0x0010
+#define TLV320AIC23_DAC_OFF 0x0008
+#define TLV320AIC23_ADC_OFF 0x0004
+#define TLV320AIC23_MIC_OFF 0x0002
+#define TLV320AIC23_LINE_OFF 0x0001
+
+/* Digital audio interface register */
+#define TLV320AIC23_MS_MASTER 0x0040
+#define TLV320AIC23_LRSWAP_ON 0x0020
+#define TLV320AIC23_LRP_ON 0x0010
+#define TLV320AIC23_IWL_16 0x0000
+#define TLV320AIC23_IWL_20 0x0004
+#define TLV320AIC23_IWL_24 0x0008
+#define TLV320AIC23_IWL_32 0x000C
+#define TLV320AIC23_FOR_I2S 0x0002
+#define TLV320AIC23_FOR_DSP 0x0003
+#define TLV320AIC23_FOR_LJUST 0x0001
+
+/* Sample rate control register */
+#define TLV320AIC23_CLKOUT_HALF 0x0080
+#define TLV320AIC23_CLKIN_HALF 0x0040
+#define TLV320AIC23_BOSR_384fs 0x0002 /* BOSR_272fs in USB mode */
+#define TLV320AIC23_USB_CLK_ON 0x0001
+#define TLV320AIC23_SR_MASK 0xf
+#define TLV320AIC23_CLKOUT_SHIFT 7
+#define TLV320AIC23_CLKIN_SHIFT 6
+#define TLV320AIC23_SR_SHIFT 2
+#define TLV320AIC23_BOSR_SHIFT 1
+
+/* Digital interface register */
+#define TLV320AIC23_ACT_ON 0x0001
+
+/*
+ * AUDIO related MACROS
+ */
+
+#define TLV320AIC23_DEFAULT_OUT_VOL 0x70
+#define TLV320AIC23_DEFAULT_IN_VOLUME 0x10
+
+#define TLV320AIC23_OUT_VOL_MIN TLV320AIC23_LHV_MIN
+#define TLV320AIC23_OUT_VOL_MAX TLV320AIC23_LHV_MAX
+#define TLV320AIC23_OUT_VO_RANGE (TLV320AIC23_OUT_VOL_MAX - \
+ TLV320AIC23_OUT_VOL_MIN)
+#define TLV320AIC23_OUT_VOL_MASK TLV320AIC23_OUT_VOL_MAX
+
+#define TLV320AIC23_IN_VOL_MIN TLV320AIC23_LIV_MIN
+#define TLV320AIC23_IN_VOL_MAX TLV320AIC23_LIV_MAX
+#define TLV320AIC23_IN_VOL_RANGE (TLV320AIC23_IN_VOL_MAX - \
+ TLV320AIC23_IN_VOL_MIN)
+#define TLV320AIC23_IN_VOL_MASK TLV320AIC23_IN_VOL_MAX
+
+#define TLV320AIC23_SIDETONE_MASK 0x1c0
+#define TLV320AIC23_SIDETONE_0 0x100
+#define TLV320AIC23_SIDETONE_6 0x000
+#define TLV320AIC23_SIDETONE_9 0x040
+#define TLV320AIC23_SIDETONE_12 0x080
+#define TLV320AIC23_SIDETONE_18 0x0c0
+
+extern struct snd_soc_dai tlv320aic23_dai;
+extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
+
+#endif /* _TLV320AIC23_H */
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 566a427c928..05336ed7e49 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -48,7 +48,6 @@
#include "tlv320aic3x.h"
-#define AUDIO_NAME "aic3x"
#define AIC3X_VERSION "0.2"
/* codec private data */
@@ -991,7 +990,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected);
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
struct snd_soc_dai aic3x_dai = {
- .name = "aic3x",
+ .name = "tlv320aic3x",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1055,7 +1054,7 @@ static int aic3x_init(struct snd_soc_device *socdev)
struct aic3x_setup_data *setup = socdev->codec_data;
int reg, ret = 0;
- codec->name = "aic3x";
+ codec->name = "tlv320aic3x";
codec->owner = THIS_MODULE;
codec->read = aic3x_read_reg_cache;
codec->write = aic3x_write;
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index d206d7f892b..a69ee72a7af 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -36,7 +36,6 @@
#include "uda1380.h"
#define UDA1380_VERSION "0.6"
-#define AUDIO_NAME "uda1380"
/*
* uda1380 register cache
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 9a37c8d95ed..d8ca2da8d63 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -3,7 +3,7 @@
*
* Copyright 2006 Wolfson Microelectronics PLC.
*
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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
@@ -18,6 +18,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -27,7 +28,6 @@
#include "wm8510.h"
-#define AUDIO_NAME "wm8510"
#define WM8510_VERSION "0.6"
struct snd_soc_codec_device soc_codec_dev_wm8510;
@@ -55,6 +55,9 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
0x0001,
};
+#define WM8510_POWER1_BIASEN 0x08
+#define WM8510_POWER1_BUFIOEN 0x10
+
/*
* read wm8510 register cache
*/
@@ -224,9 +227,9 @@ SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
-SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
- &wm8510_micpga_controls[0],
- ARRAY_SIZE(wm8510_micpga_controls)),
+SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0,
+ &wm8510_micpga_controls[0],
+ ARRAY_SIZE(wm8510_micpga_controls)),
SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
&wm8510_boost_controls[0],
ARRAY_SIZE(wm8510_boost_controls)),
@@ -526,23 +529,35 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
static int wm8510_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
switch (level) {
case SND_SOC_BIAS_ON:
- wm8510_write(codec, WM8510_POWER1, 0x1ff);
- wm8510_write(codec, WM8510_POWER2, 0x1ff);
- wm8510_write(codec, WM8510_POWER3, 0x1ff);
- break;
case SND_SOC_BIAS_PREPARE:
+ power1 |= 0x1; /* VMID 50k */
+ wm8510_write(codec, WM8510_POWER1, power1);
+ break;
+
case SND_SOC_BIAS_STANDBY:
+ power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
+
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ /* Initial cap charge at VMID 5k */
+ wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
+ mdelay(100);
+ }
+
+ power1 |= 0x2; /* VMID 500k */
+ wm8510_write(codec, WM8510_POWER1, power1);
break;
+
case SND_SOC_BIAS_OFF:
- /* everything off, dac mute, inactive */
- wm8510_write(codec, WM8510_POWER1, 0x0);
- wm8510_write(codec, WM8510_POWER2, 0x0);
- wm8510_write(codec, WM8510_POWER3, 0x0);
+ wm8510_write(codec, WM8510_POWER1, 0);
+ wm8510_write(codec, WM8510_POWER2, 0);
+ wm8510_write(codec, WM8510_POWER3, 0);
break;
}
+
codec->bias_level = level;
return 0;
}
@@ -640,6 +655,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
}
/* power on device */
+ codec->bias_level = SND_SOC_BIAS_OFF;
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
wm8510_add_controls(codec);
wm8510_add_widgets(codec);
@@ -747,6 +763,62 @@ err_driver:
}
#endif
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
+{
+ struct snd_soc_device *socdev = wm8510_socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ int ret;
+
+ codec->control_data = spi;
+
+ ret = wm8510_init(socdev);
+ if (ret < 0)
+ dev_err(&spi->dev, "failed to initialise WM8510\n");
+
+ return ret;
+}
+
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static struct spi_driver wm8510_spi_driver = {
+ .driver = {
+ .name = "wm8510",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8510_spi_probe,
+ .remove = __devexit_p(wm8510_spi_remove),
+};
+
+static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
+{
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[2];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#endif /* CONFIG_SPI_MASTER */
+
static int wm8510_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -772,8 +844,14 @@ static int wm8510_probe(struct platform_device *pdev)
codec->hw_write = (hw_write_t)i2c_master_send;
ret = wm8510_add_i2c_device(pdev, setup);
}
-#else
- /* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ if (setup->spi) {
+ codec->hw_write = (hw_write_t)wm8510_spi_write;
+ ret = spi_register_driver(&wm8510_spi_driver);
+ if (ret != 0)
+ printk(KERN_ERR "can't add spi driver");
+ }
#endif
if (ret != 0)
@@ -796,6 +874,9 @@ static int wm8510_remove(struct platform_device *pdev)
i2c_unregister_device(codec->control_data);
i2c_del_driver(&wm8510_i2c_driver);
#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8510_spi_driver);
+#endif
kfree(codec);
return 0;
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
index c5368396045..bdefcf5c69f 100644
--- a/sound/soc/codecs/wm8510.h
+++ b/sound/soc/codecs/wm8510.h
@@ -94,6 +94,7 @@
#define WM8510_MCLKDIV_12 (7 << 5)
struct wm8510_setup_data {
+ int spi;
int i2c_bus;
unsigned short i2c_address;
};
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index df1ffbe305b..627ebfb4209 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -36,7 +35,6 @@
#include "wm8580.h"
-#define AUDIO_NAME "wm8580"
#define WM8580_VERSION "0.1"
struct pll_state {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 7b64d9a7ff7..7f8a7e36b33 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -29,7 +29,6 @@
#include "wm8731.h"
-#define AUDIO_NAME "wm8731"
#define WM8731_VERSION "0.13"
struct snd_soc_codec_device soc_codec_dev_wm8731;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 4892e398a59..9b7296ee5b0 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -29,7 +29,6 @@
#include "wm8750.h"
-#define AUDIO_NAME "WM8750"
#define WM8750_VERSION "0.12"
/* codec private data */
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 8c4df44f334..d426eaa2218 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -2,8 +2,7 @@
* wm8753.c -- WM8753 ALSA Soc Audio driver
*
* Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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
@@ -40,6 +39,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -51,7 +51,6 @@
#include "wm8753.h"
-#define AUDIO_NAME "wm8753"
#define WM8753_VERSION "0.16"
static int caps_charge = 2000;
@@ -1719,6 +1718,63 @@ err_driver:
}
#endif
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
+{
+ struct snd_soc_device *socdev = wm8753_socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ int ret;
+
+ codec->control_data = spi;
+
+ ret = wm8753_init(socdev);
+ if (ret < 0)
+ dev_err(&spi->dev, "failed to initialise WM8753\n");
+
+ return ret;
+}
+
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static struct spi_driver wm8753_spi_driver = {
+ .driver = {
+ .name = "wm8753",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8753_spi_probe,
+ .remove = __devexit_p(wm8753_spi_remove),
+};
+
+static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
+{
+ struct spi_transfer t;
+ struct spi_message m;
+ u8 msg[2];
+
+ if (len <= 0)
+ return 0;
+
+ msg[0] = data[0];
+ msg[1] = data[1];
+
+ spi_message_init(&m);
+ memset(&t, 0, (sizeof t));
+
+ t.tx_buf = &msg[0];
+ t.len = len;
+
+ spi_message_add_tail(&t, &m);
+ spi_sync(spi, &m);
+
+ return len;
+}
+#endif
+
+
static int wm8753_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -1753,8 +1809,14 @@ static int wm8753_probe(struct platform_device *pdev)
codec->hw_write = (hw_write_t)i2c_master_send;
ret = wm8753_add_i2c_device(pdev, setup);
}
-#else
- /* Add other interfaces here */
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ if (setup->spi) {
+ codec->hw_write = (hw_write_t)wm8753_spi_write;
+ ret = spi_register_driver(&wm8753_spi_driver);
+ if (ret != 0)
+ printk(KERN_ERR "can't add spi driver");
+ }
#endif
if (ret != 0) {
@@ -1798,6 +1860,9 @@ static int wm8753_remove(struct platform_device *pdev)
i2c_unregister_device(codec->control_data);
i2c_del_driver(&wm8753_i2c_driver);
#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8753_spi_driver);
+#endif
kfree(codec->private_data);
kfree(codec);
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 7defde069f1..f55704ce931 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -2,8 +2,7 @@
* wm8753.h -- audio driver for WM8753
*
* Copyright 2003 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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
@@ -79,6 +78,7 @@
#define WM8753_ADCTL2 0x3f
struct wm8753_setup_data {
+ int spi;
int i2c_bus;
unsigned short i2c_address;
};
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 0b8c6d38b48..3b326c9b558 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index a3f54ec4226..ce40d787760 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -653,14 +653,14 @@ static const struct snd_kcontrol_new wm8903_snd_controls[] = {
/* Input PGAs - No TLV since the scale depends on PGA mode */
SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
- 7, 1, 0),
+ 7, 1, 1),
SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
0, 31, 0),
SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
6, 1, 0),
SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
- 7, 1, 0),
+ 7, 1, 1),
SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
0, 31, 0),
SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 974a4cd0f3f..f41a578ddd4 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -29,7 +29,6 @@
#include "wm8971.h"
-#define AUDIO_NAME "wm8971"
#define WM8971_VERSION "0.9"
#define WM8971_REG_COUNT 43
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 63410d7b5ef..572d22b0880 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -30,7 +30,6 @@
#include "wm8990.h"
-#define AUDIO_NAME "wm8990"
#define WM8990_VERSION "0.2"
/* codec private data */
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 2f1c91b1d55..ffb471e420e 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -2,8 +2,7 @@
* wm9712.c -- ALSA Soc WM9712 codec support
*
* Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 441d0580db1..aba402b3c99 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -2,8 +2,7 @@
* wm9713.c -- ALSA Soc WM9713 codec support
*
* Copyright 2006 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index aea27e70043..8b7766b998d 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -13,3 +13,11 @@ config SND_OMAP_SOC_N810
select SND_SOC_TLV320AIC3X
help
Say Y if you want to add support for SoC audio on Nokia N810.
+
+config SND_OMAP_SOC_OSK5912
+ tristate "SoC Audio support for omap osk5912"
+ depends on SND_OMAP_SOC && MACH_OMAP_OSK
+ select SND_OMAP_SOC_MCBSP
+ select SND_SOC_TLV320AIC23
+ help
+ Say Y if you want to add support for SoC audio on osk5912.
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index d8d8d58075e..e09d1f297f6 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -7,5 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
# OMAP Machine Support
snd-soc-n810-objs := n810.o
+snd-soc-osk5912-objs := osk5912.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index d166b6b2a60..fae3ad36e0b 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
int i, err;
/* Not connected */
- snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
- snd_soc_dapm_disable_pin(codec, "HPLCOM");
- snd_soc_dapm_disable_pin(codec, "HPRCOM");
+ snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
+ snd_soc_dapm_nc_pin(codec, "HPLCOM");
+ snd_soc_dapm_nc_pin(codec, "HPRCOM");
/* Add N810 specific controls */
for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 35310e16d7f..0a063a98a66 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -59,12 +59,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
* Stream DMA parameters. DMA request line and port address are set runtime
* since they are different between OMAP1 and later OMAPs
*/
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
-{
- { .name = "I2S PCM Stereo out", },
- { .name = "I2S PCM Stereo in", },
-},
-};
+static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
static const int omap1_dma_reqs[][2] = {
@@ -84,11 +79,22 @@ static const unsigned long omap1_mcbsp_port[][2] = {
static const int omap1_dma_reqs[][2] = {};
static const unsigned long omap1_mcbsp_port[][2] = {};
#endif
-#if defined(CONFIG_ARCH_OMAP2420)
-static const int omap2420_dma_reqs[][2] = {
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+static const int omap24xx_dma_reqs[][2] = {
{ OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
{ OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+ { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
+ { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
+ { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
+#endif
};
+#else
+static const int omap24xx_dma_reqs[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
static const unsigned long omap2420_mcbsp_port[][2] = {
{ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
@@ -96,10 +102,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = {
OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
};
#else
-static const int omap2420_dma_reqs[][2] = {};
static const unsigned long omap2420_mcbsp_port[][2] = {};
#endif
+#if defined(CONFIG_ARCH_OMAP2430)
+static const unsigned long omap2430_mcbsp_port[][2] = {
+ { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap2430_mcbsp_port[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const unsigned long omap34xx_mcbsp_port[][2] = {
+ { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+ { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+ OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap34xx_mcbsp_port[][2] = {};
+#endif
+
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -167,14 +206,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
dma = omap1_dma_reqs[bus_id][substream->stream];
port = omap1_mcbsp_port[bus_id][substream->stream];
} else if (cpu_is_omap2420()) {
- dma = omap2420_dma_reqs[bus_id][substream->stream];
+ dma = omap24xx_dma_reqs[bus_id][substream->stream];
port = omap2420_mcbsp_port[bus_id][substream->stream];
+ } else if (cpu_is_omap2430()) {
+ dma = omap24xx_dma_reqs[bus_id][substream->stream];
+ port = omap2430_mcbsp_port[bus_id][substream->stream];
+ } else if (cpu_is_omap343x()) {
+ dma = omap24xx_dma_reqs[bus_id][substream->stream];
+ port = omap34xx_mcbsp_port[bus_id][substream->stream];
} else {
- /*
- * TODO: Add support for 2430 and 3430
- */
return -ENODEV;
}
+ omap_mcbsp_dai_dma_params[id][substream->stream].name =
+ substream->stream ? "Audio Capture" : "Audio Playback";
omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
@@ -245,6 +289,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
regs->rcr2 |= RDATDLY(1);
regs->xcr2 |= XDATDLY(1);
break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /* 0-bit data delay */
+ regs->rcr2 |= RDATDLY(0);
+ regs->xcr2 |= XDATDLY(0);
+ break;
default:
/* Unsupported data format */
return -EINVAL;
@@ -310,7 +359,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
int clk_id)
{
int sel_bit;
- u16 reg;
+ u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
if (cpu_class_is_omap1()) {
/* OMAP1's can use only external source clock */
@@ -320,6 +369,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
return 0;
}
+ if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
+ return -EINVAL;
+
+ if (cpu_is_omap343x())
+ reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
+
switch (mcbsp_data->bus_id) {
case 0:
reg = OMAP2_CONTROL_DEVCONF0;
@@ -329,20 +384,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
reg = OMAP2_CONTROL_DEVCONF0;
sel_bit = 6;
break;
- /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+ case 2:
+ reg = reg_devconf1;
+ sel_bit = 0;
+ break;
+ case 3:
+ reg = reg_devconf1;
+ sel_bit = 2;
+ break;
+ case 4:
+ reg = reg_devconf1;
+ sel_bit = 4;
+ break;
default:
return -EINVAL;
}
- if (cpu_class_is_omap2()) {
- if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
- omap_ctrl_writel(omap_ctrl_readl(reg) &
- ~(1 << sel_bit), reg);
- } else {
- omap_ctrl_writel(omap_ctrl_readl(reg) |
- (1 << sel_bit), reg);
- }
- }
+ if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
+ omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
+ else
+ omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
return 0;
}
@@ -376,37 +437,49 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
return err;
}
-struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = {
-{
- .name = "omap-mcbsp-dai",
- .id = 0,
- .type = SND_SOC_DAI_I2S,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = OMAP_MCBSP_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = OMAP_MCBSP_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = {
- .startup = omap_mcbsp_dai_startup,
- .shutdown = omap_mcbsp_dai_shutdown,
- .trigger = omap_mcbsp_dai_trigger,
- .hw_params = omap_mcbsp_dai_hw_params,
- },
- .dai_ops = {
- .set_fmt = omap_mcbsp_dai_set_dai_fmt,
- .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
- .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
- },
- .private_data = &mcbsp_data[0].bus_id,
-},
+#define OMAP_MCBSP_DAI_BUILDER(link_id) \
+{ \
+ .name = "omap-mcbsp-dai-(link_id)", \
+ .id = (link_id), \
+ .type = SND_SOC_DAI_I2S, \
+ .playback = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = OMAP_MCBSP_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }, \
+ .capture = { \
+ .channels_min = 2, \
+ .channels_max = 2, \
+ .rates = OMAP_MCBSP_RATES, \
+ .formats = SNDRV_PCM_FMTBIT_S16_LE, \
+ }, \
+ .ops = { \
+ .startup = omap_mcbsp_dai_startup, \
+ .shutdown = omap_mcbsp_dai_shutdown, \
+ .trigger = omap_mcbsp_dai_trigger, \
+ .hw_params = omap_mcbsp_dai_hw_params, \
+ }, \
+ .dai_ops = { \
+ .set_fmt = omap_mcbsp_dai_set_dai_fmt, \
+ .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \
+ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \
+ }, \
+ .private_data = &mcbsp_data[(link_id)].bus_id, \
+}
+
+struct snd_soc_dai omap_mcbsp_dai[] = {
+ OMAP_MCBSP_DAI_BUILDER(0),
+ OMAP_MCBSP_DAI_BUILDER(1),
+#if NUM_LINKS >= 3
+ OMAP_MCBSP_DAI_BUILDER(2),
+#endif
+#if NUM_LINKS == 5
+ OMAP_MCBSP_DAI_BUILDER(3),
+ OMAP_MCBSP_DAI_BUILDER(4),
+#endif
};
+
EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index ed8afb55067..df7ad13ba73 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -38,11 +38,17 @@ enum omap_mcbsp_div {
OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */
};
-/*
- * REVISIT: Preparation for the ASoC v2. Let the number of available links to
- * be same than number of McBSP ports found in OMAP(s) we are compiling for.
- */
-#define NUM_LINKS 1
+#if defined(CONFIG_ARCH_OMAP2420)
+#define NUM_LINKS 2
+#endif
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+#undef NUM_LINKS
+#define NUM_LINKS 3
+#endif
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+#undef NUM_LINKS
+#define NUM_LINKS 5
+#endif
extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 690bfeaec4a..e9084fdd208 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
prtd->dma_data = dma_data;
err = omap_request_dma(dma_data->dma_req, dma_data->name,
omap_pcm_dma_irq, substream, &prtd->dma_ch);
- if (!cpu_is_omap1510()) {
+ if (!err & !cpu_is_omap1510()) {
/*
* Link channel with itself so DMA doesn't need any
* reprogramming while looping the buffer
@@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC;
dma_params.src_start = runtime->dma_addr;
dma_params.dst_start = dma_data->port_addr;
+ dma_params.dst_port = OMAP_DMA_PORT_MPUI;
} else {
dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT;
dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
dma_params.src_start = dma_data->port_addr;
dma_params.dst_start = runtime->dma_addr;
+ dma_params.src_port = OMAP_DMA_PORT_MPUI;
}
/*
* Set DMA transfer frame size equal to ALSA period size and frame
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
new file mode 100644
index 00000000000..0fe73379689
--- /dev/null
+++ b/sound/soc/omap/osk5912.c
@@ -0,0 +1,232 @@
+/*
+ * osk5912.c -- SoC audio for OSK 5912
+ *
+ * Copyright (C) 2008 Mistral Solutions
+ *
+ * Contact: Arun KS <arunks@mistralsolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/tlv320aic23.h"
+
+#define CODEC_CLOCK 12000000
+
+static struct clk *tlv320aic23_mclk;
+
+static int osk_startup(struct snd_pcm_substream *substream)
+{
+ return clk_enable(tlv320aic23_mclk);
+}
+
+static void osk_shutdown(struct snd_pcm_substream *substream)
+{
+ clk_disable(tlv320aic23_mclk);
+}
+
+static int osk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int err;
+
+ /* Set codec DAI configuration */
+ err = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (err < 0) {
+ printk(KERN_ERR "can't set codec DAI configuration\n");
+ return err;
+ }
+
+ /* Set cpu DAI configuration */
+ err = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (err < 0) {
+ printk(KERN_ERR "can't set cpu DAI configuration\n");
+ return err;
+ }
+
+ /* Set the codec system clock for DAC and ADC */
+ err =
+ snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
+
+ if (err < 0) {
+ printk(KERN_ERR "can't set codec system clock\n");
+ return err;
+ }
+
+ return err;
+}
+
+static struct snd_soc_ops osk_ops = {
+ .startup = osk_startup,
+ .hw_params = osk_hw_params,
+ .shutdown = osk_shutdown,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headphone Jack", NULL, "LHPOUT"},
+ {"Headphone Jack", NULL, "RHPOUT"},
+
+ {"LLINEIN", NULL, "Line In"},
+ {"RLINEIN", NULL, "Line In"},
+
+ {"MICIN", NULL, "Mic Jack"},
+};
+
+static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+
+ /* Add osk5912 specific widgets */
+ snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+ ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+ /* Set up osk5912 specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ snd_soc_dapm_enable_pin(codec, "Line In");
+ snd_soc_dapm_enable_pin(codec, "Mic Jack");
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link osk_dai = {
+ .name = "TLV320AIC23",
+ .stream_name = "AIC23",
+ .cpu_dai = &omap_mcbsp_dai[0],
+ .codec_dai = &tlv320aic23_dai,
+ .init = osk_tlv320aic23_init,
+ .ops = &osk_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_osk = {
+ .name = "OSK5912",
+ .dai_link = &osk_dai,
+ .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device osk_snd_devdata = {
+ .machine = &snd_soc_machine_osk,
+ .platform = &omap_soc_platform,
+ .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *osk_snd_device;
+
+static int __init osk_soc_init(void)
+{
+ int err;
+ u32 curRate;
+ struct device *dev;
+
+ if (!(machine_is_omap_osk()))
+ return -ENODEV;
+
+ osk_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!osk_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
+ osk_snd_devdata.dev = &osk_snd_device->dev;
+ *(unsigned int *)osk_dai.cpu_dai->private_data = 0; /* McBSP1 */
+ err = platform_device_add(osk_snd_device);
+ if (err)
+ goto err1;
+
+ dev = &osk_snd_device->dev;
+
+ tlv320aic23_mclk = clk_get(dev, "mclk");
+ if (IS_ERR(tlv320aic23_mclk)) {
+ printk(KERN_ERR "Could not get mclk clock\n");
+ return -ENODEV;
+ }
+
+ if (clk_get_usecount(tlv320aic23_mclk) > 0) {
+ /* MCLK is already in use */
+ printk(KERN_WARNING
+ "MCLK in use at %d Hz. We change it to %d Hz\n",
+ (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
+ }
+
+ /*
+ * Configure 12 MHz output on MCLK.
+ */
+ curRate = (uint) clk_get_rate(tlv320aic23_mclk);
+ if (curRate != CODEC_CLOCK) {
+ if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
+ printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
+ err = -ECANCELED;
+ goto err1;
+ }
+ }
+
+ printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
+ (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
+ clk_get_usecount(tlv320aic23_mclk));
+
+ return 0;
+err1:
+ clk_put(tlv320aic23_mclk);
+ platform_device_del(osk_snd_device);
+ platform_device_put(osk_snd_device);
+
+ return err;
+
+}
+
+static void __exit osk_soc_exit(void)
+{
+ platform_device_unregister(osk_snd_device);
+}
+
+module_init(osk_soc_init);
+module_exit(osk_soc_exit);
+
+MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
+MODULE_DESCRIPTION("ALSA SoC OSK 5912");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 1a8373de7f3..2718eaf7895 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -4,7 +4,7 @@
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
*
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
* Richard Purdie <richard@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -281,8 +281,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
{
int i, err;
- snd_soc_dapm_disable_pin(codec, "LLINEIN");
- snd_soc_dapm_disable_pin(codec, "RLINEIN");
+ snd_soc_dapm_nc_pin(codec, "LLINEIN");
+ snd_soc_dapm_nc_pin(codec, "RLINEIN");
/* Add corgi specific controls */
for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
index d9c3f7b28be..e6ff6929ab4 100644
--- a/sound/soc/pxa/em-x270.c
+++ b/sound/soc/pxa/em-x270.c
@@ -9,7 +9,7 @@
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
*
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
* Richard Purdie <richard@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify it
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index f84f7d8db09..4d9930c5278 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -4,7 +4,7 @@
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
*
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
* Richard Purdie <richard@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -242,8 +242,8 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
{
int i, err;
- snd_soc_dapm_disable_pin(codec, "LLINEIN");
- snd_soc_dapm_disable_pin(codec, "RLINEIN");
+ snd_soc_dapm_nc_pin(codec, "LLINEIN");
+ snd_soc_dapm_nc_pin(codec, "RLINEIN");
snd_soc_dapm_enable_pin(codec, "MICIN");
/* Add poodle specific controls */
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 2fb58298513..e758034db5c 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -3,7 +3,7 @@
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * lrg@slimlogic.co.uk
*
* 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
@@ -405,6 +405,6 @@ module_init(pxa2xx_i2s_init);
module_exit(pxa2xx_i2s_exit);
/* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 9a70b00fc30..d307b6757e9 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -4,7 +4,7 @@
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
*
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
* Richard Purdie <richard@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -281,13 +281,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
int i, err;
/* NC codec pins */
- snd_soc_dapm_disable_pin(codec, "RINPUT1");
- snd_soc_dapm_disable_pin(codec, "LINPUT2");
- snd_soc_dapm_disable_pin(codec, "RINPUT2");
- snd_soc_dapm_disable_pin(codec, "LINPUT3");
- snd_soc_dapm_disable_pin(codec, "RINPUT3");
- snd_soc_dapm_disable_pin(codec, "OUT3");
- snd_soc_dapm_disable_pin(codec, "MONO1");
+ snd_soc_dapm_nc_pin(codec, "RINPUT1");
+ snd_soc_dapm_nc_pin(codec, "LINPUT2");
+ snd_soc_dapm_nc_pin(codec, "RINPUT2");
+ snd_soc_dapm_nc_pin(codec, "LINPUT3");
+ snd_soc_dapm_nc_pin(codec, "RINPUT3");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "MONO1");
/* Add spitz specific controls */
for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 2baaa750f12..afefe41b8c4 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -4,7 +4,7 @@
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
*
- * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
* Richard Purdie <richard@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -190,8 +190,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec)
{
int i, err;
- snd_soc_dapm_disable_pin(codec, "OUT3");
- snd_soc_dapm_disable_pin(codec, "MONOOUT");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "MONOOUT");
/* add tosa specific controls */
for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 73a50e93a9a..87ddfefcc2f 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -511,21 +511,20 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
DBG("Entered %s\n", __func__);
/* set up NC codec pins */
- snd_soc_dapm_disable_pin(codec, "LOUT2");
- snd_soc_dapm_disable_pin(codec, "ROUT2");
- snd_soc_dapm_disable_pin(codec, "OUT3");
- snd_soc_dapm_disable_pin(codec, "OUT4");
- snd_soc_dapm_disable_pin(codec, "LINE1");
- snd_soc_dapm_disable_pin(codec, "LINE2");
-
-
- /* set endpoints to default mode */
- set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+ snd_soc_dapm_nc_pin(codec, "LOUT2");
+ snd_soc_dapm_nc_pin(codec, "ROUT2");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "OUT4");
+ snd_soc_dapm_nc_pin(codec, "LINE1");
+ snd_soc_dapm_nc_pin(codec, "LINE2");
/* Add neo1973 specific widgets */
snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
ARRAY_SIZE(wm8753_dapm_widgets));
+ /* set endpoints to default mode */
+ set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
/* add neo1973 specific controls */
for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
err = snd_ctl_add(codec->card,
@@ -603,6 +602,8 @@ static int lm4857_i2c_probe(struct i2c_client *client,
{
DBG("Entered %s\n", __func__);
+ i2c = client;
+
lm4857_write_regs();
return 0;
}
@@ -611,6 +612,8 @@ static int lm4857_i2c_remove(struct i2c_client *client)
{
DBG("Entered %s\n", __func__);
+ i2c = NULL;
+
return 0;
}
@@ -650,7 +653,7 @@ static void lm4857_shutdown(struct i2c_client *dev)
}
static const struct i2c_device_id lm4857_i2c_id[] = {
- { "neo1973_lm4857", 0 }
+ { "neo1973_lm4857", 0 },
{ }
};
@@ -668,48 +671,6 @@ static struct i2c_driver lm4857_i2c_driver = {
};
static struct platform_device *neo1973_snd_device;
-static struct i2c_client *lm4857_client;
-
-static int __init neo1973_add_lm4857_device(struct platform_device *pdev,
- int i2c_bus,
- unsigned short i2c_address)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&lm4857_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add lm4857 driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = i2c_address;
- strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- lm4857_client = client;
- return 0;
-
-err_driver:
- i2c_del_driver(&lm4857_i2c_driver);
- return -ENODEV;
-}
static int __init neo1973_init(void)
{
@@ -736,8 +697,8 @@ static int __init neo1973_init(void)
return ret;
}
- ret = neo1973_add_lm4857_device(neo1973_snd_device,
- neo1973_wm8753_setup, 0x7C);
+ ret = i2c_add_driver(&lm4857_i2c_driver);
+
if (ret != 0)
platform_device_unregister(neo1973_snd_device);
@@ -748,7 +709,6 @@ static void __exit neo1973_exit(void)
{
DBG("Entered %s\n", __func__);
- i2c_unregister_device(lm4857_client);
i2c_del_driver(&lm4857_i2c_driver);
platform_device_unregister(neo1973_snd_device);
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ad381138fc2..462e635dfc7 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -4,8 +4,7 @@
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
*
- * Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* with code, comments and ideas from :-
* Richard Purdie <richard@openedhand.com>
*
@@ -1886,7 +1885,7 @@ module_init(snd_soc_init);
module_exit(snd_soc_exit);
/* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("ALSA SoC Core");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 9ca9c08610f..efbd0b37810 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2,8 +2,7 @@
* soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
*
* Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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
@@ -1484,6 +1483,26 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
/**
+ * snd_soc_dapm_nc_pin - permanently disable pin.
+ * @codec: SoC codec
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets. At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
+{
+ return snd_soc_dapm_set_pin(codec, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
+
+/**
* snd_soc_dapm_get_pin_status - get audio pin status
* @codec: audio codec
* @pin: audio signal pin endpoint (or start point)
@@ -1521,6 +1540,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
/* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
MODULE_LICENSE("GPL");
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 49acee0c484..f87933e4881 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -1,6 +1,6 @@
/*
* Driver for AMD7930 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
*
* Based entirely upon drivers/sbus/audio/amd7930.c which is:
* Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -35,6 +35,8 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -44,7 +46,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/sbus.h>
#include <asm/prom.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
@@ -335,8 +336,8 @@ struct snd_amd7930 {
int pgain;
int mgain;
+ struct of_device *op;
unsigned int irq;
- unsigned int regs_size;
struct snd_amd7930 *next;
};
@@ -905,13 +906,16 @@ static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd)
static int snd_amd7930_free(struct snd_amd7930 *amd)
{
+ struct of_device *op = amd->op;
+
amd7930_idle(amd);
if (amd->irq)
free_irq(amd->irq, amd);
if (amd->regs)
- sbus_iounmap(amd->regs, amd->regs_size);
+ of_iounmap(&op->resource[0], amd->regs,
+ resource_size(&op->resource[0]));
kfree(amd);
@@ -930,13 +934,12 @@ static struct snd_device_ops snd_amd7930_dev_ops = {
};
static int __devinit snd_amd7930_create(struct snd_card *card,
- struct resource *rp,
- unsigned int reg_size,
+ struct of_device *op,
int irq, int dev,
struct snd_amd7930 **ramd)
{
- unsigned long flags;
struct snd_amd7930 *amd;
+ unsigned long flags;
int err;
*ramd = NULL;
@@ -946,9 +949,10 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
spin_lock_init(&amd->lock);
amd->card = card;
- amd->regs_size = reg_size;
+ amd->op = op;
- amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
+ amd->regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]), "amd7930");
if (!amd->regs) {
snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
return -EIO;
@@ -997,12 +1001,15 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
return 0;
}
-static int __devinit amd7930_attach_common(struct resource *rp, int irq)
+static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
+ struct resource *rp = &op->resource[0];
static int dev_num;
struct snd_card *card;
struct snd_amd7930 *amd;
- int err;
+ int err, irq;
+
+ irq = op->irqs[0];
if (dev_num >= SNDRV_CARDS)
return -ENODEV;
@@ -1023,8 +1030,7 @@ static int __devinit amd7930_attach_common(struct resource *rp, int irq)
(unsigned long long)rp->start,
irq);
- if ((err = snd_amd7930_create(card, rp,
- (rp->end - rp->start) + 1,
+ if ((err = snd_amd7930_create(card, op,
irq, dev_num, &amd)) < 0)
goto out_err;
@@ -1049,43 +1055,7 @@ out_err:
return err;
}
-static int __devinit amd7930_obio_attach(struct device_node *dp)
-{
- const struct linux_prom_registers *regs;
- const struct linux_prom_irqs *irqp;
- struct resource res, *rp;
- int len;
-
- irqp = of_get_property(dp, "intr", &len);
- if (!irqp) {
- snd_printk("%s: Firmware node lacks IRQ property.\n",
- dp->full_name);
- return -ENODEV;
- }
-
- regs = of_get_property(dp, "reg", &len);
- if (!regs) {
- snd_printk("%s: Firmware node lacks register property.\n",
- dp->full_name);
- return -ENODEV;
- }
-
- rp = &res;
- rp->start = regs->phys_addr;
- rp->end = rp->start + regs->reg_size - 1;
- rp->flags = IORESOURCE_IO | (regs->which_io & 0xff);
-
- return amd7930_attach_common(rp, irqp->pri);
-}
-
-static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
- return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]);
-}
-
-static struct of_device_id amd7930_match[] = {
+static const struct of_device_id amd7930_match[] = {
{
.name = "audio",
},
@@ -1100,20 +1070,7 @@ static struct of_platform_driver amd7930_sbus_driver = {
static int __init amd7930_init(void)
{
- struct device_node *dp;
-
- /* Try to find the sun4c "audio" node first. */
- dp = of_find_node_by_path("/");
- dp = dp->child;
- while (dp) {
- if (!strcmp(dp->name, "audio"))
- amd7930_obio_attach(dp);
-
- dp = dp->sibling;
- }
-
- /* Probe each SBUS for amd7930 chips. */
- return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&amd7930_sbus_driver, &of_bus_type);
}
static void __exit amd7930_exit(void)
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 791d2fb821d..d44bf98e965 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1,6 +1,6 @@
/*
* Driver for CS4231 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
*
* Based entirely upon drivers/sbus/audio/cs4231.c which is:
* Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -17,7 +17,8 @@
#include <linux/moduleparam.h>
#include <linux/irq.h>
#include <linux/io.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -29,13 +30,12 @@
#ifdef CONFIG_SBUS
#define SBUS_SUPPORT
-#include <asm/sbus.h>
#endif
#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
#define EBUS_SUPPORT
#include <linux/pci.h>
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
#endif
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
@@ -70,8 +70,6 @@ struct cs4231_dma_control {
int (*request)(struct cs4231_dma_control *dma_cont,
dma_addr_t bus_addr, size_t len);
unsigned int (*address)(struct cs4231_dma_control *dma_cont);
- void (*preallocate)(struct snd_cs4231 *chip,
- struct snd_pcm *pcm);
#ifdef EBUS_SUPPORT
struct ebus_dma_info ebus_info;
#endif
@@ -114,21 +112,12 @@ struct snd_cs4231 {
struct mutex mce_mutex; /* mutex for mce register */
struct mutex open_mutex; /* mutex for ALSA open/close */
- union {
-#ifdef SBUS_SUPPORT
- struct sbus_dev *sdev;
-#endif
-#ifdef EBUS_SUPPORT
- struct pci_dev *pdev;
-#endif
- } dev_u;
+ struct of_device *op;
unsigned int irq[2];
unsigned int regs_size;
struct snd_cs4231 *next;
};
-static struct snd_cs4231 *cs4231_list;
-
/* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for
* now.... -DaveM
*/
@@ -267,27 +256,19 @@ static unsigned char snd_cs4231_original_image[32] =
static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr)
{
-#ifdef EBUS_SUPPORT
if (cp->flags & CS4231_FLAG_EBUS)
return readb(reg_addr);
else
-#endif
-#ifdef SBUS_SUPPORT
return sbus_readb(reg_addr);
-#endif
}
static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val,
void __iomem *reg_addr)
{
-#ifdef EBUS_SUPPORT
if (cp->flags & CS4231_FLAG_EBUS)
return writeb(val, reg_addr);
else
-#endif
-#ifdef SBUS_SUPPORT
return sbus_writeb(val, reg_addr);
-#endif
}
/*
@@ -1258,7 +1239,9 @@ static int __init snd_cs4231_pcm(struct snd_card *card)
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
strcpy(pcm->name, "CS4231");
- chip->p_dma.preallocate(chip, pcm);
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ &chip->op->dev,
+ 64 * 1024, 128 * 1024);
chip->pcm = pcm;
@@ -1627,8 +1610,7 @@ static int __init cs4231_attach_finish(struct snd_card *card)
if (err < 0)
goto out_err;
- chip->next = cs4231_list;
- cs4231_list = chip;
+ dev_set_drvdata(&chip->op->dev, chip);
dev++;
return 0;
@@ -1783,24 +1765,19 @@ static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont)
return sbus_readl(base->regs + base->dir + APCVA);
}
-static void sbus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
- snd_dma_sbus_data(chip->dev_u.sdev),
- 64 * 1024, 128 * 1024);
-}
-
/*
* Init and exit routines
*/
static int snd_cs4231_sbus_free(struct snd_cs4231 *chip)
{
+ struct of_device *op = chip->op;
+
if (chip->irq[0])
free_irq(chip->irq[0], chip);
if (chip->port)
- sbus_iounmap(chip->port, chip->regs_size);
+ of_iounmap(&op->resource[0], chip->port, chip->regs_size);
return 0;
}
@@ -1817,7 +1794,7 @@ static struct snd_device_ops snd_cs4231_sbus_dev_ops = {
};
static int __init snd_cs4231_sbus_create(struct snd_card *card,
- struct sbus_dev *sdev,
+ struct of_device *op,
int dev)
{
struct snd_cs4231 *chip = card->private_data;
@@ -1828,13 +1805,13 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
spin_lock_init(&chip->p_dma.sbus_info.lock);
mutex_init(&chip->mce_mutex);
mutex_init(&chip->open_mutex);
- chip->dev_u.sdev = sdev;
- chip->regs_size = sdev->reg_addrs[0].reg_size;
+ chip->op = op;
+ chip->regs_size = resource_size(&op->resource[0]);
memcpy(&chip->image, &snd_cs4231_original_image,
sizeof(snd_cs4231_original_image));
- chip->port = sbus_ioremap(&sdev->resource[0], 0,
- chip->regs_size, "cs4231");
+ chip->port = of_ioremap(&op->resource[0], 0,
+ chip->regs_size, "cs4231");
if (!chip->port) {
snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
return -EIO;
@@ -1849,22 +1826,20 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
chip->p_dma.enable = sbus_dma_enable;
chip->p_dma.request = sbus_dma_request;
chip->p_dma.address = sbus_dma_addr;
- chip->p_dma.preallocate = sbus_dma_preallocate;
chip->c_dma.prepare = sbus_dma_prepare;
chip->c_dma.enable = sbus_dma_enable;
chip->c_dma.request = sbus_dma_request;
chip->c_dma.address = sbus_dma_addr;
- chip->c_dma.preallocate = sbus_dma_preallocate;
- if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
+ if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt,
IRQF_SHARED, "cs4231", chip)) {
snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n",
- dev, sdev->irqs[0]);
+ dev, op->irqs[0]);
snd_cs4231_sbus_free(chip);
return -EBUSY;
}
- chip->irq[0] = sdev->irqs[0];
+ chip->irq[0] = op->irqs[0];
if (snd_cs4231_probe(chip) < 0) {
snd_cs4231_sbus_free(chip);
@@ -1881,9 +1856,9 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
return 0;
}
-static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
+static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
- struct resource *rp = &sdev->resource[0];
+ struct resource *rp = &op->resource[0];
struct snd_card *card;
int err;
@@ -1895,9 +1870,9 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
card->shortname,
rp->flags & 0xffL,
(unsigned long long)rp->start,
- sdev->irqs[0]);
+ op->irqs[0]);
- err = snd_cs4231_sbus_create(card, sdev, dev);
+ err = snd_cs4231_sbus_create(card, op, dev);
if (err < 0) {
snd_card_free(card);
return err;
@@ -1950,30 +1925,25 @@ static unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont)
return ebus_dma_addr(&dma_cont->ebus_info);
}
-static void _ebus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->dev_u.pdev),
- 64*1024, 128*1024);
-}
-
/*
* Init and exit routines
*/
static int snd_cs4231_ebus_free(struct snd_cs4231 *chip)
{
+ struct of_device *op = chip->op;
+
if (chip->c_dma.ebus_info.regs) {
ebus_dma_unregister(&chip->c_dma.ebus_info);
- iounmap(chip->c_dma.ebus_info.regs);
+ of_iounmap(&op->resource[2], chip->c_dma.ebus_info.regs, 0x10);
}
if (chip->p_dma.ebus_info.regs) {
ebus_dma_unregister(&chip->p_dma.ebus_info);
- iounmap(chip->p_dma.ebus_info.regs);
+ of_iounmap(&op->resource[1], chip->p_dma.ebus_info.regs, 0x10);
}
if (chip->port)
- iounmap(chip->port);
+ of_iounmap(&op->resource[0], chip->port, 0x10);
return 0;
}
@@ -1990,7 +1960,7 @@ static struct snd_device_ops snd_cs4231_ebus_dev_ops = {
};
static int __init snd_cs4231_ebus_create(struct snd_card *card,
- struct linux_ebus_device *edev,
+ struct of_device *op,
int dev)
{
struct snd_cs4231 *chip = card->private_data;
@@ -2002,35 +1972,35 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card,
mutex_init(&chip->mce_mutex);
mutex_init(&chip->open_mutex);
chip->flags |= CS4231_FLAG_EBUS;
- chip->dev_u.pdev = edev->bus->self;
+ chip->op = op;
memcpy(&chip->image, &snd_cs4231_original_image,
sizeof(snd_cs4231_original_image));
strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)");
chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
chip->c_dma.ebus_info.client_cookie = chip;
- chip->c_dma.ebus_info.irq = edev->irqs[0];
+ chip->c_dma.ebus_info.irq = op->irqs[0];
strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
chip->p_dma.ebus_info.client_cookie = chip;
- chip->p_dma.ebus_info.irq = edev->irqs[1];
+ chip->p_dma.ebus_info.irq = op->irqs[1];
chip->p_dma.prepare = _ebus_dma_prepare;
chip->p_dma.enable = _ebus_dma_enable;
chip->p_dma.request = _ebus_dma_request;
chip->p_dma.address = _ebus_dma_addr;
- chip->p_dma.preallocate = _ebus_dma_preallocate;
chip->c_dma.prepare = _ebus_dma_prepare;
chip->c_dma.enable = _ebus_dma_enable;
chip->c_dma.request = _ebus_dma_request;
chip->c_dma.address = _ebus_dma_addr;
- chip->c_dma.preallocate = _ebus_dma_preallocate;
- chip->port = ioremap(edev->resource[0].start, 0x10);
- chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10);
- chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10);
+ chip->port = of_ioremap(&op->resource[0], 0, 0x10, "cs4231");
+ chip->p_dma.ebus_info.regs =
+ of_ioremap(&op->resource[1], 0, 0x10, "cs4231_pdma");
+ chip->c_dma.ebus_info.regs =
+ of_ioremap(&op->resource[2], 0, 0x10, "cs4231_cdma");
if (!chip->port || !chip->p_dma.ebus_info.regs ||
!chip->c_dma.ebus_info.regs) {
snd_cs4231_ebus_free(chip);
@@ -2078,7 +2048,7 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card,
return 0;
}
-static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
+static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match)
{
struct snd_card *card;
int err;
@@ -2089,10 +2059,10 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname,
- edev->resource[0].start,
- edev->irqs[0]);
+ op->resource[0].start,
+ op->irqs[0]);
- err = snd_cs4231_ebus_create(card, edev, dev);
+ err = snd_cs4231_ebus_create(card, op, dev);
if (err < 0) {
snd_card_free(card);
return err;
@@ -2102,68 +2072,57 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
}
#endif
-static int __init cs4231_init(void)
+static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match)
{
-#ifdef SBUS_SUPPORT
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
-#endif
#ifdef EBUS_SUPPORT
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
+ if (!strcmp(op->node->parent->name, "ebus"))
+ return cs4231_ebus_probe(op, match);
#endif
- int found;
-
- found = 0;
-
#ifdef SBUS_SUPPORT
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
- if (cs4231_sbus_attach(sdev) == 0)
- found++;
- }
- }
+ if (!strcmp(op->node->parent->name, "sbus") ||
+ !strcmp(op->node->parent->name, "sbi"))
+ return cs4231_sbus_probe(op, match);
#endif
-#ifdef EBUS_SUPPORT
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- int match = 0;
-
- if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
- match = 1;
- } else if (!strcmp(edev->prom_node->name, "audio")) {
- const char *compat;
-
- compat = of_get_property(edev->prom_node,
- "compatible", NULL);
- if (compat && !strcmp(compat, "SUNW,CS4231"))
- match = 1;
- }
+ return -ENODEV;
+}
- if (match &&
- cs4231_ebus_attach(edev) == 0)
- found++;
- }
- }
-#endif
+static int __devexit cs4231_remove(struct of_device *op)
+{
+ struct snd_cs4231 *chip = dev_get_drvdata(&op->dev);
+ snd_card_free(chip->card);
- return (found > 0) ? 0 : -EIO;
+ return 0;
}
-static void __exit cs4231_exit(void)
-{
- struct snd_cs4231 *p = cs4231_list;
+static const struct of_device_id cs4231_match[] = {
+ {
+ .name = "SUNW,CS4231",
+ },
+ {
+ .name = "audio",
+ .compatible = "SUNW,CS4231",
+ },
+ {},
+};
- while (p != NULL) {
- struct snd_cs4231 *next = p->next;
+MODULE_DEVICE_TABLE(of, cs4231_match);
- snd_card_free(p->card);
+static struct of_platform_driver cs4231_driver = {
+ .name = "audio",
+ .match_table = cs4231_match,
+ .probe = cs4231_probe,
+ .remove = __devexit_p(cs4231_remove),
+};
- p = next;
- }
+static int __init cs4231_init(void)
+{
+ return of_register_driver(&cs4231_driver, &of_bus_type);
+}
- cs4231_list = NULL;
+static void __exit cs4231_exit(void)
+{
+ of_unregister_driver(&cs4231_driver);
}
module_init(cs4231_init);
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index c534a2a849f..c257ad8bdfb 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -57,6 +57,7 @@
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -66,7 +67,7 @@
#include <sound/initval.h>
#include <linux/of.h>
-#include <asm/sbus.h>
+#include <linux/of_device.h>
#include <asm/atomic.h>
MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
@@ -297,7 +298,7 @@ struct dbri_streaminfo {
/* This structure holds the information for both chips (DBRI & CS4215) */
struct snd_dbri {
int regs_size, irq; /* Needed for unload */
- struct sbus_dev *sdev; /* SBUS device info */
+ struct of_device *op; /* OF device info */
spinlock_t lock;
struct dbri_dma *dma; /* Pointer to our DMA block */
@@ -2093,14 +2094,15 @@ static int snd_dbri_hw_params(struct snd_pcm_substream *substream,
*/
if (info->dvma_buffer == 0) {
if (DBRI_STREAMNO(substream) == DBRI_PLAY)
- direction = SBUS_DMA_TODEVICE;
+ direction = DMA_TO_DEVICE;
else
- direction = SBUS_DMA_FROMDEVICE;
+ direction = DMA_FROM_DEVICE;
- info->dvma_buffer = sbus_map_single(dbri->sdev,
- runtime->dma_area,
- params_buffer_bytes(hw_params),
- direction);
+ info->dvma_buffer =
+ dma_map_single(&dbri->op->dev,
+ runtime->dma_area,
+ params_buffer_bytes(hw_params),
+ direction);
}
direction = params_buffer_bytes(hw_params);
@@ -2121,12 +2123,12 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream)
*/
if (info->dvma_buffer) {
if (DBRI_STREAMNO(substream) == DBRI_PLAY)
- direction = SBUS_DMA_TODEVICE;
+ direction = DMA_TO_DEVICE;
else
- direction = SBUS_DMA_FROMDEVICE;
+ direction = DMA_FROM_DEVICE;
- sbus_unmap_single(dbri->sdev, info->dvma_buffer,
- substream->runtime->buffer_size, direction);
+ dma_unmap_single(&dbri->op->dev, info->dvma_buffer,
+ substream->runtime->buffer_size, direction);
info->dvma_buffer = 0;
}
if (info->pipe != -1) {
@@ -2519,31 +2521,32 @@ static void __devinit snd_dbri_proc(struct snd_card *card)
static void snd_dbri_free(struct snd_dbri *dbri);
static int __devinit snd_dbri_create(struct snd_card *card,
- struct sbus_dev *sdev,
- int irq, int dev)
+ struct of_device *op,
+ int irq, int dev)
{
struct snd_dbri *dbri = card->private_data;
int err;
spin_lock_init(&dbri->lock);
- dbri->sdev = sdev;
+ dbri->op = op;
dbri->irq = irq;
- dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
- &dbri->dma_dvma);
+ dbri->dma = dma_alloc_coherent(&op->dev,
+ sizeof(struct dbri_dma),
+ &dbri->dma_dvma, GFP_ATOMIC);
memset((void *)dbri->dma, 0, sizeof(struct dbri_dma));
dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n",
dbri->dma, dbri->dma_dvma);
/* Map the registers into memory. */
- dbri->regs_size = sdev->reg_addrs[0].reg_size;
- dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
- dbri->regs_size, "DBRI Registers");
+ dbri->regs_size = resource_size(&op->resource[0]);
+ dbri->regs = of_ioremap(&op->resource[0], 0,
+ dbri->regs_size, "DBRI Registers");
if (!dbri->regs) {
printk(KERN_ERR "DBRI: could not allocate registers\n");
- sbus_free_consistent(sdev, sizeof(struct dbri_dma),
- (void *)dbri->dma, dbri->dma_dvma);
+ dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
return -EIO;
}
@@ -2551,9 +2554,9 @@ static int __devinit snd_dbri_create(struct snd_card *card,
"DBRI audio", dbri);
if (err) {
printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
- sbus_iounmap(dbri->regs, dbri->regs_size);
- sbus_free_consistent(sdev, sizeof(struct dbri_dma),
- (void *)dbri->dma, dbri->dma_dvma);
+ of_iounmap(&op->resource[0], dbri->regs, dbri->regs_size);
+ dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
return err;
}
@@ -2577,27 +2580,23 @@ static void snd_dbri_free(struct snd_dbri *dbri)
free_irq(dbri->irq, dbri);
if (dbri->regs)
- sbus_iounmap(dbri->regs, dbri->regs_size);
+ of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size);
if (dbri->dma)
- sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
- (void *)dbri->dma, dbri->dma_dvma);
+ dma_free_coherent(&dbri->op->dev,
+ sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
}
-static int __devinit dbri_probe(struct of_device *of_dev,
- const struct of_device_id *match)
+static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match)
{
- struct sbus_dev *sdev = to_sbus_device(&of_dev->dev);
struct snd_dbri *dbri;
- int irq;
struct resource *rp;
struct snd_card *card;
static int dev = 0;
+ int irq;
int err;
- dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n",
- sdev->prom_name, sdev->slot);
-
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
@@ -2605,7 +2604,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
return -ENOENT;
}
- irq = sdev->irqs[0];
+ irq = op->irqs[0];
if (irq <= 0) {
printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
return -ENODEV;
@@ -2618,12 +2617,12 @@ static int __devinit dbri_probe(struct of_device *of_dev,
strcpy(card->driver, "DBRI");
strcpy(card->shortname, "Sun DBRI");
- rp = &sdev->resource[0];
+ rp = &op->resource[0];
sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
card->shortname,
rp->flags & 0xffL, (unsigned long long)rp->start, irq);
- err = snd_dbri_create(card, sdev, irq, dev);
+ err = snd_dbri_create(card, op, irq, dev);
if (err < 0) {
snd_card_free(card);
return err;
@@ -2640,7 +2639,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
/* /proc file handling */
snd_dbri_proc(card);
- dev_set_drvdata(&of_dev->dev, card);
+ dev_set_drvdata(&op->dev, card);
err = snd_card_register(card);
if (err < 0)
@@ -2648,7 +2647,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
dev, dbri->regs,
- dbri->irq, sdev->prom_name[9], dbri->mm.version);
+ dbri->irq, op->node->name[9], dbri->mm.version);
dev++;
return 0;
@@ -2659,19 +2658,19 @@ _err:
return err;
}
-static int __devexit dbri_remove(struct of_device *dev)
+static int __devexit dbri_remove(struct of_device *op)
{
- struct snd_card *card = dev_get_drvdata(&dev->dev);
+ struct snd_card *card = dev_get_drvdata(&op->dev);
snd_dbri_free(card->private_data);
snd_card_free(card);
- dev_set_drvdata(&dev->dev, NULL);
+ dev_set_drvdata(&op->dev, NULL);
return 0;
}
-static struct of_device_id dbri_match[] = {
+static const struct of_device_id dbri_match[] = {
{
.name = "SUNW,DBRIe",
},
@@ -2693,7 +2692,7 @@ static struct of_platform_driver dbri_sbus_driver = {
/* Probe for the dbri chip and then attach the driver. */
static int __init dbri_init(void)
{
- return of_register_driver(&dbri_sbus_driver, &sbus_bus_type);
+ return of_register_driver(&dbri_sbus_driver, &of_bus_type);
}
static void __exit dbri_exit(void)